go-plist-master/ 0000755 0000000 0000000 00000000000 12737755636 012630 5 ustar root root go-plist-master/text_test.go 0000644 0000000 0000000 00000002522 12737755636 015203 0 ustar root root package plist
import (
"bytes"
"io/ioutil"
"testing"
)
func BenchmarkOpenStepGenerate(b *testing.B) {
for i := 0; i < b.N; i++ {
d := newTextPlistGenerator(ioutil.Discard, OpenStepFormat)
d.generateDocument(plistValueTree)
}
}
func BenchmarkOpenStepParse(b *testing.B) {
buf := bytes.NewReader([]byte(plistValueTreeAsOpenStep))
b.ResetTimer()
for i := 0; i < b.N; i++ {
b.StartTimer()
d := newTextPlistParser(buf)
d.parseDocument()
b.StopTimer()
buf.Seek(0, 0)
}
}
func BenchmarkGNUStepParse(b *testing.B) {
buf := bytes.NewReader([]byte(plistValueTreeAsGNUStep))
b.ResetTimer()
for i := 0; i < b.N; i++ {
b.StartTimer()
d := newTextPlistParser(buf)
d.parseDocument()
b.StopTimer()
buf.Seek(0, 0)
}
}
func TestTextCommentDecode(t *testing.T) {
var testData = `{
A=1 /* A is 1 because it is the first letter */;
B=2; // B is 2 because comment-to-end-of-line.
C=3;
S = /not/a/comment/;
S2 = /not*a/*comm*en/t;
}`
type D struct {
A, B, C int
S string
S2 string
}
actual := D{1, 2, 3, "/not/a/comment/", "/not*a/*comm*en/t"}
var parsed D
buf := bytes.NewReader([]byte(testData))
decoder := NewDecoder(buf)
err := decoder.Decode(&parsed)
if err != nil {
t.Error(err.Error())
}
if actual != parsed {
t.Logf("Expected: %#v", actual)
t.Logf("Received: %#v", parsed)
t.Fail()
}
}
go-plist-master/encode_test.go 0000644 0000000 0000000 00000012374 12737755636 015462 0 ustar root root package plist
import (
"bytes"
"fmt"
"testing"
)
func BenchmarkXMLEncode(b *testing.B) {
for i := 0; i < b.N; i++ {
NewEncoder(&bytes.Buffer{}).Encode(plistValueTreeRawData)
}
}
func BenchmarkBplistEncode(b *testing.B) {
for i := 0; i < b.N; i++ {
NewBinaryEncoder(&bytes.Buffer{}).Encode(plistValueTreeRawData)
}
}
func BenchmarkOpenStepEncode(b *testing.B) {
for i := 0; i < b.N; i++ {
NewEncoderForFormat(&bytes.Buffer{}, OpenStepFormat).Encode(plistValueTreeRawData)
}
}
func TestEncode(t *testing.T) {
var failed bool
for _, test := range tests {
failed = false
t.Logf("Testing Encode (%s)", test.Name)
// A test that should render no output!
errors := make(map[int]error)
if test.ShouldFail && len(test.Expected) == 0 {
_, err := Marshal(test.Data, XMLFormat)
failed = failed || (test.ShouldFail && err == nil)
}
results := make(map[int][]byte)
for fmt, dat := range test.Expected {
results[fmt], errors[fmt] = Marshal(test.Data, fmt)
failed = failed || (test.ShouldFail && errors[fmt] == nil)
failed = failed || !bytes.Equal(dat, results[fmt])
}
if failed {
t.Logf("Value: %#v", test.Data)
if test.ShouldFail {
t.Logf("Expected: Error")
} else {
printype := "%s"
for fmt, dat := range test.Expected {
if fmt == BinaryFormat {
printype = "%+v"
} else {
printype = "%s"
}
t.Logf("Expected %s: "+printype+"\n", FormatNames[fmt], dat)
}
}
printype := "%s"
for fmt, dat := range results {
if fmt == BinaryFormat {
printype = "%+v"
} else {
printype = "%s"
}
t.Logf("Received %s: "+printype+"\n", FormatNames[fmt], dat)
}
for fmt, err := range errors {
if err != nil {
t.Logf("Error %s: %v\n", FormatNames[fmt], err)
}
}
t.Log("FAILED")
t.Fail()
}
}
}
func ExampleEncoder_Encode() {
type sparseBundleHeader struct {
InfoDictionaryVersion string `plist:"CFBundleInfoDictionaryVersion"`
BandSize uint64 `plist:"band-size"`
BackingStoreVersion int `plist:"bundle-backingstore-version"`
DiskImageBundleType string `plist:"diskimage-bundle-type"`
Size uint64 `plist:"size"`
}
data := &sparseBundleHeader{
InfoDictionaryVersion: "6.0",
BandSize: 8388608,
Size: 4 * 1048576 * 1024 * 1024,
DiskImageBundleType: "com.apple.diskimage.sparsebundle",
BackingStoreVersion: 1,
}
buf := &bytes.Buffer{}
encoder := NewEncoder(buf)
err := encoder.Encode(data)
if err != nil {
fmt.Println(err)
}
fmt.Println(buf.String())
// Output:
//
// CFBundleInfoDictionaryVersion6.0band-size8388608bundle-backingstore-version1diskimage-bundle-typecom.apple.diskimage.sparsebundlesize4398046511104
}
func ExampleMarshal_xml() {
type sparseBundleHeader struct {
InfoDictionaryVersion string `plist:"CFBundleInfoDictionaryVersion"`
BandSize uint64 `plist:"band-size"`
BackingStoreVersion int `plist:"bundle-backingstore-version"`
DiskImageBundleType string `plist:"diskimage-bundle-type"`
Size uint64 `plist:"size"`
}
data := &sparseBundleHeader{
InfoDictionaryVersion: "6.0",
BandSize: 8388608,
Size: 4 * 1048576 * 1024 * 1024,
DiskImageBundleType: "com.apple.diskimage.sparsebundle",
BackingStoreVersion: 1,
}
plist, err := MarshalIndent(data, XMLFormat, "\t")
if err != nil {
fmt.Println(err)
}
fmt.Println(string(plist))
// Output:
//
//
//
// CFBundleInfoDictionaryVersion
// 6.0
// band-size
// 8388608
// bundle-backingstore-version
// 1
// diskimage-bundle-type
// com.apple.diskimage.sparsebundle
// size
// 4398046511104
//
//
}
func ExampleMarshal_gnustep() {
type sparseBundleHeader struct {
InfoDictionaryVersion string `plist:"CFBundleInfoDictionaryVersion"`
BandSize uint64 `plist:"band-size"`
BackingStoreVersion int `plist:"bundle-backingstore-version"`
DiskImageBundleType string `plist:"diskimage-bundle-type"`
Size uint64 `plist:"size"`
}
data := &sparseBundleHeader{
InfoDictionaryVersion: "6.0",
BandSize: 8388608,
Size: 4 * 1048576 * 1024 * 1024,
DiskImageBundleType: "com.apple.diskimage.sparsebundle",
BackingStoreVersion: 1,
}
plist, err := MarshalIndent(data, GNUStepFormat, "\t")
if err != nil {
fmt.Println(err)
}
fmt.Println(string(plist))
// Output: {
// CFBundleInfoDictionaryVersion = 6.0;
// band-size = <*I8388608>;
// bundle-backingstore-version = <*I1>;
// diskimage-bundle-type = com.apple.diskimage.sparsebundle;
// size = <*I4398046511104>;
// }
}
go-plist-master/marshal_test.go 0000644 0000000 0000000 00000001466 12737755636 015654 0 ustar root root package plist
import (
"reflect"
"testing"
"time"
)
func BenchmarkStructMarshal(b *testing.B) {
for i := 0; i < b.N; i++ {
e := &Encoder{}
e.marshal(reflect.ValueOf(plistValueTreeRawData))
}
}
func BenchmarkMapMarshal(b *testing.B) {
data := map[string]interface{}{
"intarray": []interface{}{
int(1),
int8(8),
int16(16),
int32(32),
int64(64),
uint(2),
uint8(9),
uint16(17),
uint32(33),
uint64(65),
},
"floats": []interface{}{
float32(32.0),
float64(64.0),
},
"booleans": []bool{
true,
false,
},
"strings": []string{
"Hello, ASCII",
"Hello, 世界",
},
"data": []byte{1, 2, 3, 4},
"date": time.Date(2013, 11, 27, 0, 34, 0, 0, time.UTC),
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
e := &Encoder{}
e.marshal(reflect.ValueOf(data))
}
}
go-plist-master/text_tables.go 0000644 0000000 0000000 00000001176 12737755636 015502 0 ustar root root package plist
// Bitmap of characters that must be inside a quoted string
// when written to an old-style property list
// Low bits represent lower characters, and each uint64 represents 64 characters.
var gsQuotable = [4]uint64{
0x78001385ffffffff,
0xa800000138000000,
0xffffffffffffffff,
0xffffffffffffffff,
}
// 7f instead of 3f in the top line: CFOldStylePlist.c says . is valid, but they quote it.
var osQuotable = [4]uint64{
0xf4007f6fffffffff,
0xf8000001f8000001,
0xffffffffffffffff,
0xffffffffffffffff,
}
var whitespace = [4]uint64{
0x0000000100003f00,
0x0000000000000000,
0x0000000000000000,
0x0000000000000000,
}
go-plist-master/typeinfo.go 0000644 0000000 0000000 00000010266 12737755636 015021 0 ustar root root package plist
import (
"reflect"
"strings"
"sync"
)
// typeInfo holds details for the plist representation of a type.
type typeInfo struct {
fields []fieldInfo
}
// fieldInfo holds details for the plist representation of a single field.
type fieldInfo struct {
idx []int
name string
omitEmpty bool
}
var tinfoMap = make(map[reflect.Type]*typeInfo)
var tinfoLock sync.RWMutex
// getTypeInfo returns the typeInfo structure with details necessary
// for marshalling and unmarshalling typ.
func getTypeInfo(typ reflect.Type) (*typeInfo, error) {
tinfoLock.RLock()
tinfo, ok := tinfoMap[typ]
tinfoLock.RUnlock()
if ok {
return tinfo, nil
}
tinfo = &typeInfo{}
if typ.Kind() == reflect.Struct {
n := typ.NumField()
for i := 0; i < n; i++ {
f := typ.Field(i)
if f.PkgPath != "" || f.Tag.Get("plist") == "-" {
continue // Private field
}
// For embedded structs, embed its fields.
if f.Anonymous {
t := f.Type
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
if t.Kind() == reflect.Struct {
inner, err := getTypeInfo(t)
if err != nil {
return nil, err
}
for _, finfo := range inner.fields {
finfo.idx = append([]int{i}, finfo.idx...)
if err := addFieldInfo(typ, tinfo, &finfo); err != nil {
return nil, err
}
}
continue
}
}
finfo, err := structFieldInfo(typ, &f)
if err != nil {
return nil, err
}
// Add the field if it doesn't conflict with other fields.
if err := addFieldInfo(typ, tinfo, finfo); err != nil {
return nil, err
}
}
}
tinfoLock.Lock()
tinfoMap[typ] = tinfo
tinfoLock.Unlock()
return tinfo, nil
}
// structFieldInfo builds and returns a fieldInfo for f.
func structFieldInfo(typ reflect.Type, f *reflect.StructField) (*fieldInfo, error) {
finfo := &fieldInfo{idx: f.Index}
// Split the tag from the xml namespace if necessary.
tag := f.Tag.Get("plist")
// Parse flags.
tokens := strings.Split(tag, ",")
tag = tokens[0]
if len(tokens) > 1 {
tag = tokens[0]
for _, flag := range tokens[1:] {
switch flag {
case "omitempty":
finfo.omitEmpty = true
}
}
}
if tag == "" {
// If the name part of the tag is completely empty,
// use the field name
finfo.name = f.Name
return finfo, nil
}
finfo.name = tag
return finfo, nil
}
// addFieldInfo adds finfo to tinfo.fields if there are no
// conflicts, or if conflicts arise from previous fields that were
// obtained from deeper embedded structures than finfo. In the latter
// case, the conflicting entries are dropped.
// A conflict occurs when the path (parent + name) to a field is
// itself a prefix of another path, or when two paths match exactly.
// It is okay for field paths to share a common, shorter prefix.
func addFieldInfo(typ reflect.Type, tinfo *typeInfo, newf *fieldInfo) error {
var conflicts []int
// First, figure all conflicts. Most working code will have none.
for i := range tinfo.fields {
oldf := &tinfo.fields[i]
if newf.name == oldf.name {
conflicts = append(conflicts, i)
}
}
// Without conflicts, add the new field and return.
if conflicts == nil {
tinfo.fields = append(tinfo.fields, *newf)
return nil
}
// If any conflict is shallower, ignore the new field.
// This matches the Go field resolution on embedding.
for _, i := range conflicts {
if len(tinfo.fields[i].idx) < len(newf.idx) {
return nil
}
}
// Otherwise, the new field is shallower, and thus takes precedence,
// so drop the conflicting fields from tinfo and append the new one.
for c := len(conflicts) - 1; c >= 0; c-- {
i := conflicts[c]
copy(tinfo.fields[i:], tinfo.fields[i+1:])
tinfo.fields = tinfo.fields[:len(tinfo.fields)-1]
}
tinfo.fields = append(tinfo.fields, *newf)
return nil
}
// value returns v's field value corresponding to finfo.
// It's equivalent to v.FieldByIndex(finfo.idx), but initializes
// and dereferences pointers as necessary.
func (finfo *fieldInfo) value(v reflect.Value) reflect.Value {
for i, x := range finfo.idx {
if i > 0 {
t := v.Type()
if t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct {
if v.IsNil() {
v.Set(reflect.New(v.Type().Elem()))
}
v = v.Elem()
}
}
v = v.Field(x)
}
return v
}
go-plist-master/unmarshal_test.go 0000644 0000000 0000000 00000001236 12737755636 016212 0 ustar root root package plist
import (
"reflect"
"testing"
"time"
)
func BenchmarkStructUnmarshal(b *testing.B) {
type Data struct {
Intarray []uint64 `plist:"intarray"`
Floats []float64 `plist:"floats"`
Booleans []bool `plist:"booleans"`
Strings []string `plist:"strings"`
Dat []byte `plist:"data"`
Date time.Time `plist:"date"`
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
var xval Data
d := &Decoder{}
d.unmarshal(plistValueTree, reflect.ValueOf(&xval))
}
}
func BenchmarkInterfaceUnmarshal(b *testing.B) {
for i := 0; i < b.N; i++ {
var xval interface{}
d := &Decoder{}
d.unmarshal(plistValueTree, reflect.ValueOf(&xval))
}
}
go-plist-master/must.go 0000644 0000000 0000000 00000001373 12737755636 014153 0 ustar root root package plist
import (
"io"
"strconv"
)
type mustWriter struct {
io.Writer
}
func (w mustWriter) Write(p []byte) (int, error) {
n, err := w.Writer.Write(p)
if err != nil {
panic(err)
}
return n, nil
}
func mustParseInt(str string, base, bits int) int64 {
i, err := strconv.ParseInt(str, base, bits)
if err != nil {
panic(err)
}
return i
}
func mustParseUint(str string, base, bits int) uint64 {
i, err := strconv.ParseUint(str, base, bits)
if err != nil {
panic(err)
}
return i
}
func mustParseFloat(str string, bits int) float64 {
i, err := strconv.ParseFloat(str, bits)
if err != nil {
panic(err)
}
return i
}
func mustParseBool(str string) bool {
i, err := strconv.ParseBool(str)
if err != nil {
panic(err)
}
return i
}
go-plist-master/doc.go 0000644 0000000 0000000 00000000533 12737755636 013725 0 ustar root root // Package plist implements encoding and decoding of Apple's "property list" format.
// Property lists come in three sorts: plain text (GNUStep and OpenStep), XML and binary.
// plist supports all of them.
// The mapping between property list and Go objects is described in the documentation for the Marshal and Unmarshal functions.
package plist
go-plist-master/fuzz.go 0000644 0000000 0000000 00000000327 12737755636 014157 0 ustar root root // +build gofuzz
package plist
import (
"bytes"
)
func Fuzz(data []byte) int {
buf := bytes.NewReader(data)
var obj interface{}
if err := NewDecoder(buf).Decode(&obj); err != nil {
return 0
}
return 1
}
go-plist-master/decode_test.go 0000644 0000000 0000000 00000015601 12737755636 015444 0 ustar root root package plist
import (
"bytes"
"fmt"
"reflect"
"testing"
)
func BenchmarkXMLDecode(b *testing.B) {
for i := 0; i < b.N; i++ {
b.StopTimer()
var bval interface{}
buf := bytes.NewReader([]byte(plistValueTreeAsXML))
b.StartTimer()
decoder := NewDecoder(buf)
decoder.Decode(bval)
b.StopTimer()
}
}
func BenchmarkBplistDecode(b *testing.B) {
for i := 0; i < b.N; i++ {
b.StopTimer()
var bval interface{}
buf := bytes.NewReader(plistValueTreeAsBplist)
b.StartTimer()
decoder := NewDecoder(buf)
decoder.Decode(bval)
b.StopTimer()
}
}
func TestLaxDecode(t *testing.T) {
var laxTestDataStringsOnlyAsXML = `{B=1;D="2013-11-27 00:34:00 +0000";I64=1;F64="3.0";U64=2;}`
d := LaxTestData{}
buf := bytes.NewReader([]byte(laxTestDataStringsOnlyAsXML))
decoder := NewDecoder(buf)
decoder.lax = true
err := decoder.Decode(&d)
if err != nil {
t.Error(err.Error())
}
if d != laxTestData {
t.Logf("Expected: %#v", laxTestData)
t.Logf("Received: %#v", d)
t.Fail()
}
}
func TestIllegalLaxDecode(t *testing.T) {
i := int64(0)
u := uint64(0)
f := float64(0)
b := false
plists := []struct {
pl string
d interface{}
}{
{"abc", &i},
{"abc", &u},
{"def", &f},
{"ghi", &b},
{"jkl", []byte{0x00}},
}
for _, plist := range plists {
buf := bytes.NewReader([]byte(plist.pl))
decoder := NewDecoder(buf)
decoder.lax = true
err := decoder.Decode(plist.d)
t.Logf("Error: %v", err)
if err == nil {
t.Error("Expected error, received nothing.")
}
}
}
func TestIllegalDecode(t *testing.T) {
i := int64(0)
b := false
plists := []struct {
pl string
d interface{}
}{
{"abc", &i},
{"ABC=", &i},
{"34.1", &i},
{"def", &i},
{"2010-01-01T00:00:00Z", &i},
{"0", &b},
{"0", &b},
{"a0", &b},
{"", &[1]int{1}},
}
for _, plist := range plists {
buf := bytes.NewReader([]byte(plist.pl))
decoder := NewDecoder(buf)
err := decoder.Decode(plist.d)
t.Logf("Error: %v", err)
if err == nil {
t.Error("Expected error, received nothing.")
}
}
}
func TestDecode(t *testing.T) {
var failed bool
for _, test := range tests {
failed = false
t.Logf("Testing Decode (%s)", test.Name)
d := test.DecodeData
if d == nil {
d = test.Data
}
testData := reflect.ValueOf(d)
if !testData.IsValid() || isEmptyInterface(testData) {
continue
}
if testData.Kind() == reflect.Ptr || testData.Kind() == reflect.Interface {
testData = testData.Elem()
}
d = testData.Interface()
results := make(map[int]interface{})
errors := make(map[int]error)
for fmt, dat := range test.Expected {
if test.SkipDecode[fmt] {
continue
}
val := reflect.New(testData.Type()).Interface()
_, errors[fmt] = Unmarshal(dat, val)
vt := reflect.ValueOf(val)
if vt.Kind() == reflect.Ptr || vt.Kind() == reflect.Interface {
vt = vt.Elem()
val = vt.Interface()
}
results[fmt] = val
if !reflect.DeepEqual(d, val) {
failed = true
}
}
if results[BinaryFormat] != nil && results[XMLFormat] != nil {
if !reflect.DeepEqual(results[BinaryFormat], results[XMLFormat]) {
t.Log("Binary and XML decoding yielded different values.")
t.Log("Binary:", results[BinaryFormat])
t.Log("XML :", results[XMLFormat])
failed = true
}
}
if failed {
t.Logf("Expected: %#v\n", d)
for fmt, dat := range results {
t.Logf("Received %s: %#v\n", FormatNames[fmt], dat)
}
for fmt, err := range errors {
if err != nil {
t.Logf("Error %s: %v\n", FormatNames[fmt], err)
}
}
t.Log("FAILED")
t.Fail()
}
}
}
func TestInterfaceDecode(t *testing.T) {
var xval interface{}
buf := bytes.NewReader([]byte{98, 112, 108, 105, 115, 116, 48, 48, 214, 1, 13, 17, 21, 25, 27, 2, 14, 18, 22, 26, 28, 88, 105, 110, 116, 97, 114, 114, 97, 121, 170, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 16, 1, 16, 8, 16, 16, 16, 32, 16, 64, 16, 2, 16, 9, 16, 17, 16, 33, 16, 65, 86, 102, 108, 111, 97, 116, 115, 162, 15, 16, 34, 66, 0, 0, 0, 35, 64, 80, 0, 0, 0, 0, 0, 0, 88, 98, 111, 111, 108, 101, 97, 110, 115, 162, 19, 20, 9, 8, 87, 115, 116, 114, 105, 110, 103, 115, 162, 23, 24, 92, 72, 101, 108, 108, 111, 44, 32, 65, 83, 67, 73, 73, 105, 0, 72, 0, 101, 0, 108, 0, 108, 0, 111, 0, 44, 0, 32, 78, 22, 117, 76, 84, 100, 97, 116, 97, 68, 1, 2, 3, 4, 84, 100, 97, 116, 101, 51, 65, 184, 69, 117, 120, 0, 0, 0, 8, 21, 30, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 68, 71, 76, 85, 94, 97, 98, 99, 107, 110, 123, 142, 147, 152, 157, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 166})
decoder := NewDecoder(buf)
err := decoder.Decode(&xval)
if err != nil {
t.Log("Error:", err)
t.Fail()
}
}
func TestFormatDetection(t *testing.T) {
type formatTest struct {
expectedFormat int
data []byte
}
plists := []formatTest{
{BinaryFormat, []byte{98, 112, 108, 105, 115, 116, 48, 48, 85, 72, 101, 108, 108, 111, 8, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14}},
{XMLFormat, []byte(`<*I3>`)},
{InvalidFormat, []byte(`bplist00`)}, // Looks like a binary property list, and bplist does not have fallbacks(!)
{OpenStepFormat, []byte(`(1,2,3,4,5)`)},
{OpenStepFormat, []byte(``)},
{GNUStepFormat, []byte(`(1,2,<*I3>)`)},
{OpenStepFormat, []byte{0x00}},
}
for _, fmttest := range plists {
fmt, err := Unmarshal(fmttest.data, nil)
if fmt != fmttest.expectedFormat {
t.Errorf("Wanted %s, received %s.", FormatNames[fmttest.expectedFormat], FormatNames[fmt])
}
if err != nil {
t.Logf("Error: %v", err)
}
}
}
func ExampleDecoder_Decode() {
type sparseBundleHeader struct {
InfoDictionaryVersion string `plist:"CFBundleInfoDictionaryVersion"`
BandSize uint64 `plist:"band-size"`
BackingStoreVersion int `plist:"bundle-backingstore-version"`
DiskImageBundleType string `plist:"diskimage-bundle-type"`
Size uint64 `plist:"size"`
}
buf := bytes.NewReader([]byte(`
CFBundleInfoDictionaryVersion
6.0
band-size
8388608
bundle-backingstore-version
1
diskimage-bundle-type
com.apple.diskimage.sparsebundle
size
4398046511104
`))
var data sparseBundleHeader
decoder := NewDecoder(buf)
err := decoder.Decode(&data)
if err != nil {
fmt.Println(err)
}
fmt.Println(data)
// Output: {6.0 8388608 1 com.apple.diskimage.sparsebundle 4398046511104}
}
go-plist-master/LICENSE 0000644 0000000 0000000 00000006350 12737755636 013641 0 ustar root root Copyright (c) 2013, Dustin L. Howett. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
--------------------------------------------------------------------------------
Parts of this package were made available under the license covering
the Go language and all attended core libraries. That license follows.
--------------------------------------------------------------------------------
Copyright (c) 2012 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
go-plist-master/xml.go 0000644 0000000 0000000 00000016456 12737755636 013773 0 ustar root root package plist
import (
"encoding/base64"
"encoding/xml"
"errors"
"fmt"
"io"
"math"
"runtime"
"strings"
"time"
)
const xmlDOCTYPE = `
`
type xmlPlistGenerator struct {
writer io.Writer
xmlEncoder *xml.Encoder
}
func (p *xmlPlistGenerator) generateDocument(pval *plistValue) {
io.WriteString(p.writer, xml.Header)
io.WriteString(p.writer, xmlDOCTYPE)
plistStartElement := xml.StartElement{
Name: xml.Name{
Space: "",
Local: "plist",
},
Attr: []xml.Attr{{
Name: xml.Name{
Space: "",
Local: "version"},
Value: "1.0"},
},
}
p.xmlEncoder.EncodeToken(plistStartElement)
p.writePlistValue(pval)
p.xmlEncoder.EncodeToken(plistStartElement.End())
p.xmlEncoder.Flush()
}
func (p *xmlPlistGenerator) writePlistValue(pval *plistValue) {
if pval == nil {
return
}
defer p.xmlEncoder.Flush()
key := ""
encodedValue := pval.value
switch pval.kind {
case Dictionary:
startElement := xml.StartElement{Name: xml.Name{Local: "dict"}}
p.xmlEncoder.EncodeToken(startElement)
dict := encodedValue.(*dictionary)
dict.populateArrays()
for i, k := range dict.keys {
p.xmlEncoder.EncodeElement(k, xml.StartElement{Name: xml.Name{Local: "key"}})
p.writePlistValue(dict.values[i])
}
p.xmlEncoder.EncodeToken(startElement.End())
case Array:
startElement := xml.StartElement{Name: xml.Name{Local: "array"}}
p.xmlEncoder.EncodeToken(startElement)
values := encodedValue.([]*plistValue)
for _, v := range values {
p.writePlistValue(v)
}
p.xmlEncoder.EncodeToken(startElement.End())
case String:
key = "string"
case Integer:
key = "integer"
if pval.value.(signedInt).signed {
encodedValue = int64(pval.value.(signedInt).value)
} else {
encodedValue = pval.value.(signedInt).value
}
case Real:
key = "real"
encodedValue = pval.value.(sizedFloat).value
switch {
case math.IsInf(pval.value.(sizedFloat).value, 1):
encodedValue = "inf"
case math.IsInf(pval.value.(sizedFloat).value, -1):
encodedValue = "-inf"
case math.IsNaN(pval.value.(sizedFloat).value):
encodedValue = "nan"
}
case Boolean:
key = "false"
b := pval.value.(bool)
if b {
key = "true"
}
encodedValue = ""
case Data:
key = "data"
encodedValue = xml.CharData(base64.StdEncoding.EncodeToString(pval.value.([]byte)))
case Date:
key = "date"
encodedValue = pval.value.(time.Time).In(time.UTC).Format(time.RFC3339)
}
if key != "" {
err := p.xmlEncoder.EncodeElement(encodedValue, xml.StartElement{Name: xml.Name{Local: key}})
if err != nil {
panic(err)
}
}
}
func (p *xmlPlistGenerator) Indent(i string) {
p.xmlEncoder.Indent("", i)
}
func newXMLPlistGenerator(w io.Writer) *xmlPlistGenerator {
mw := mustWriter{w}
return &xmlPlistGenerator{mw, xml.NewEncoder(mw)}
}
type xmlPlistParser struct {
reader io.Reader
xmlDecoder *xml.Decoder
whitespaceReplacer *strings.Replacer
ntags int
}
func (p *xmlPlistParser) parseDocument() (pval *plistValue, parseError error) {
defer func() {
if r := recover(); r != nil {
if _, ok := r.(runtime.Error); ok {
panic(r)
}
if _, ok := r.(invalidPlistError); ok {
parseError = r.(error)
} else {
// Wrap all non-invalid-plist errors.
parseError = plistParseError{"XML", r.(error)}
}
}
}()
for {
if token, err := p.xmlDecoder.Token(); err == nil {
if element, ok := token.(xml.StartElement); ok {
pval = p.parseXMLElement(element)
if p.ntags == 0 {
panic(invalidPlistError{"XML", errors.New("no elements encountered")})
}
return
}
} else {
// The first XML parse turned out to be invalid:
// we do not have an XML property list.
panic(invalidPlistError{"XML", err})
}
}
}
func (p *xmlPlistParser) parseXMLElement(element xml.StartElement) *plistValue {
var charData xml.CharData
switch element.Name.Local {
case "plist":
p.ntags++
for {
token, err := p.xmlDecoder.Token()
if err != nil {
panic(err)
}
if el, ok := token.(xml.EndElement); ok && el.Name.Local == "plist" {
break
}
if el, ok := token.(xml.StartElement); ok {
return p.parseXMLElement(el)
}
}
return nil
case "string":
p.ntags++
err := p.xmlDecoder.DecodeElement(&charData, &element)
if err != nil {
panic(err)
}
return &plistValue{String, string(charData)}
case "integer":
p.ntags++
err := p.xmlDecoder.DecodeElement(&charData, &element)
if err != nil {
panic(err)
}
s := string(charData)
if len(s) == 0 {
panic(errors.New("invalid empty "))
}
if s[0] == '-' {
n := mustParseInt(string(charData), 10, 64)
return &plistValue{Integer, signedInt{uint64(n), true}}
} else {
n := mustParseUint(string(charData), 10, 64)
return &plistValue{Integer, signedInt{n, false}}
}
case "real":
p.ntags++
err := p.xmlDecoder.DecodeElement(&charData, &element)
if err != nil {
panic(err)
}
n := mustParseFloat(string(charData), 64)
return &plistValue{Real, sizedFloat{n, 64}}
case "true", "false":
p.ntags++
p.xmlDecoder.Skip()
b := element.Name.Local == "true"
return &plistValue{Boolean, b}
case "date":
p.ntags++
err := p.xmlDecoder.DecodeElement(&charData, &element)
if err != nil {
panic(err)
}
t, err := time.ParseInLocation(time.RFC3339, string(charData), time.UTC)
if err != nil {
panic(err)
}
return &plistValue{Date, t}
case "data":
p.ntags++
err := p.xmlDecoder.DecodeElement(&charData, &element)
if err != nil {
panic(err)
}
str := p.whitespaceReplacer.Replace(string(charData))
l := base64.StdEncoding.DecodedLen(len(str))
bytes := make([]uint8, l)
l, err = base64.StdEncoding.Decode(bytes, []byte(str))
if err != nil {
panic(err)
}
return &plistValue{Data, bytes[:l]}
case "dict":
p.ntags++
var key *string
var subvalues map[string]*plistValue = make(map[string]*plistValue)
for {
token, err := p.xmlDecoder.Token()
if err != nil {
panic(err)
}
if el, ok := token.(xml.EndElement); ok && el.Name.Local == "dict" {
if key != nil {
panic(errors.New("missing value in dictionary"))
}
break
}
if el, ok := token.(xml.StartElement); ok {
if el.Name.Local == "key" {
var k string
p.xmlDecoder.DecodeElement(&k, &el)
key = &k
} else {
if key == nil {
panic(errors.New("missing key in dictionary"))
}
subvalues[*key] = p.parseXMLElement(el)
key = nil
}
}
}
return &plistValue{Dictionary, &dictionary{m: subvalues}}
case "array":
p.ntags++
var subvalues []*plistValue = make([]*plistValue, 0, 10)
for {
token, err := p.xmlDecoder.Token()
if err != nil {
panic(err)
}
if el, ok := token.(xml.EndElement); ok && el.Name.Local == "array" {
break
}
if el, ok := token.(xml.StartElement); ok {
subvalues = append(subvalues, p.parseXMLElement(el))
}
}
return &plistValue{Array, subvalues}
}
err := fmt.Errorf("encountered unknown element %s", element.Name.Local)
if p.ntags == 0 {
// If out first XML tag is invalid, it might be an openstep data element, ala or <0101>
panic(invalidPlistError{"XML", err})
}
panic(err)
}
func newXMLPlistParser(r io.Reader) *xmlPlistParser {
return &xmlPlistParser{r, xml.NewDecoder(r), strings.NewReplacer("\t", "", "\n", "", " ", "", "\r", ""), 0}
}
go-plist-master/encode.go 0000644 0000000 0000000 00000007560 12737755636 014424 0 ustar root root package plist
import (
"bytes"
"errors"
"io"
"reflect"
"runtime"
)
type generator interface {
generateDocument(*plistValue)
Indent(string)
}
// An Encoder writes a property list to an output stream.
type Encoder struct {
writer io.Writer
format int
indent string
}
// Encode writes the property list encoding of v to the stream.
func (p *Encoder) Encode(v interface{}) (err error) {
defer func() {
if r := recover(); r != nil {
if _, ok := r.(runtime.Error); ok {
panic(r)
}
err = r.(error)
}
}()
pval := p.marshal(reflect.ValueOf(v))
if pval == nil {
panic(errors.New("plist: no root element to encode"))
}
var g generator
switch p.format {
case XMLFormat:
g = newXMLPlistGenerator(p.writer)
case BinaryFormat, AutomaticFormat:
g = newBplistGenerator(p.writer)
case OpenStepFormat, GNUStepFormat:
g = newTextPlistGenerator(p.writer, p.format)
}
g.Indent(p.indent)
g.generateDocument(pval)
return
}
// Indent turns on pretty-printing for the XML and Text property list formats.
// Each element begins on a new line and is preceded by one or more copies of indent according to its nesting depth.
func (p *Encoder) Indent(indent string) {
p.indent = indent
}
// NewEncoder returns an Encoder that writes an XML property list to w.
func NewEncoder(w io.Writer) *Encoder {
return NewEncoderForFormat(w, XMLFormat)
}
// NewEncoderForFormat returns an Encoder that writes a property list to w in the specified format.
// Pass AutomaticFormat to allow the library to choose the best encoding (currently BinaryFormat).
func NewEncoderForFormat(w io.Writer, format int) *Encoder {
return &Encoder{
writer: w,
format: format,
}
}
// NewBinaryEncoder returns an Encoder that writes a binary property list to w.
func NewBinaryEncoder(w io.Writer) *Encoder {
return NewEncoderForFormat(w, BinaryFormat)
}
// Marshal returns the property list encoding of v in the specified format.
//
// Pass AutomaticFormat to allow the library to choose the best encoding (currently BinaryFormat).
//
// Marshal traverses the value v recursively.
// Any nil values encountered, other than the root, will be silently discarded as
// the property list format bears no representation for nil values.
//
// Strings, integers of varying size, floats and booleans are encoded unchanged.
// Strings bearing non-ASCII runes will be encoded differently depending upon the property list format:
// UTF-8 for XML property lists and UTF-16 for binary property lists.
//
// Slice and Array values are encoded as property list arrays, except for
// []byte values, which are encoded as data.
//
// Map values encode as dictionaries. The map's key type must be string; there is no provision for encoding non-string dictionary keys.
//
// Struct values are encoded as dictionaries, with only exported fields being serialized. Struct field encoding may be influenced with the use of tags.
// The tag format is:
//
// `plist:"[,flags...]"`
//
// The following flags are supported:
//
// omitempty Only include the field if it is not set to the zero value for its type.
//
// If the key is "-", the field is ignored.
//
// Anonymous struct fields are encoded as if their exported fields were exposed via the outer struct.
//
// Pointer values encode as the value pointed to.
//
// Channel, complex and function values cannot be encoded. Any attempt to do so causes Marshal to return an error.
func Marshal(v interface{}, format int) ([]byte, error) {
return MarshalIndent(v, format, "")
}
// MarshalIndent works like Marshal, but each property list element
// begins on a new line and is preceded by one or more copies of indent according to its nesting depth.
func MarshalIndent(v interface{}, format int, indent string) ([]byte, error) {
buf := &bytes.Buffer{}
enc := NewEncoderForFormat(buf, format)
enc.Indent(indent)
if err := enc.Encode(v); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
go-plist-master/plist.go 0000644 0000000 0000000 00000004424 12737755636 014316 0 ustar root root package plist
import (
"reflect"
"sort"
)
// Property list format constants
const (
// Used by Decoder to represent an invalid property list.
InvalidFormat int = 0
// Used to indicate total abandon with regards to Encoder's output format.
AutomaticFormat = 0
XMLFormat = 1
BinaryFormat = 2
OpenStepFormat = 3
GNUStepFormat = 4
)
var FormatNames = map[int]string{
InvalidFormat: "unknown/invalid",
XMLFormat: "XML",
BinaryFormat: "Binary",
OpenStepFormat: "OpenStep",
GNUStepFormat: "GNUStep",
}
type plistKind uint
const (
Invalid plistKind = iota
Dictionary
Array
String
Integer
Real
Boolean
Data
Date
)
var plistKindNames map[plistKind]string = map[plistKind]string{
Invalid: "invalid",
Dictionary: "dictionary",
Array: "array",
String: "string",
Integer: "integer",
Real: "real",
Boolean: "boolean",
Data: "data",
Date: "date",
}
type plistValue struct {
kind plistKind
value interface{}
}
type signedInt struct {
value uint64
signed bool
}
type sizedFloat struct {
value float64
bits int
}
type dictionary struct {
count int
m map[string]*plistValue
keys sort.StringSlice
values []*plistValue
}
func (d *dictionary) Len() int {
return d.count
}
func (d *dictionary) Less(i, j int) bool {
return d.keys.Less(i, j)
}
func (d *dictionary) Swap(i, j int) {
d.keys.Swap(i, j)
d.values[i], d.values[j] = d.values[j], d.values[i]
}
func (d *dictionary) populateArrays() {
if d.count > 0 {
return
}
l := len(d.m)
d.count = l
d.keys = make([]string, l)
d.values = make([]*plistValue, l)
i := 0
for k, v := range d.m {
d.keys[i] = k
d.values[i] = v
i++
}
sort.Sort(d)
}
type unknownTypeError struct {
typ reflect.Type
}
func (u *unknownTypeError) Error() string {
return "plist: can't marshal value of type " + u.typ.String()
}
type invalidPlistError struct {
format string
err error
}
func (e invalidPlistError) Error() string {
s := "plist: invalid " + e.format + " property list"
if e.err != nil {
s += ": " + e.err.Error()
}
return s
}
type plistParseError struct {
format string
err error
}
func (e plistParseError) Error() string {
s := "plist: error parsing " + e.format + " property list"
if e.err != nil {
s += ": " + e.err.Error()
}
return s
}
go-plist-master/xml_test.go 0000644 0000000 0000000 00000002601 12737755636 015015 0 ustar root root package plist
import (
"bytes"
"io/ioutil"
"testing"
)
func BenchmarkXMLGenerate(b *testing.B) {
for i := 0; i < b.N; i++ {
d := newXMLPlistGenerator(ioutil.Discard)
d.generateDocument(plistValueTree)
}
}
func BenchmarkXMLParse(b *testing.B) {
buf := bytes.NewReader([]byte(plistValueTreeAsXML))
b.ResetTimer()
for i := 0; i < b.N; i++ {
b.StartTimer()
d := newXMLPlistParser(buf)
d.parseDocument()
b.StopTimer()
buf.Seek(0, 0)
}
}
func TestVariousIllegalXMLPlists(t *testing.T) {
plists := []string{
"helo",
"helo",
"helo",
"helo",
"helo",
"*@&%#helo",
"*@&%#helo",
"*@&%#helo",
"10",
"10",
"10",
"10",
"10",
"",
"",
"",
"",
"