diff --git a/.gitignore b/.gitignore
index df9c7997..9504cfaf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,3 @@
-.bitrise.secrets.yml
-.bitrise
-out/
_tmp
+.gows*
+.bitrise*
\ No newline at end of file
diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json
index 087b55a5..5d4437c9 100644
--- a/Godeps/Godeps.json
+++ b/Godeps/Godeps.json
@@ -1,58 +1,66 @@
{
"ImportPath": "github.com/bitrise-io/steps-xcode-archive",
- "GoVersion": "go1.7",
+ "GoVersion": "go1.8",
"GodepVersion": "v79",
"Packages": [
"./..."
],
"Deps": [
- {
- "ImportPath": "github.com/DHowett/go-plist",
- "Rev": "fd61394c0abc85ba629ff8471fa35d4309cd6609"
- },
{
"ImportPath": "github.com/bitrise-io/go-utils/colorstring",
- "Rev": "e9b911a4cdf5eda62401973d0c299e7e42637315"
+ "Rev": "9c30a7825aa1064e423a0f1dba751fec990b07be"
},
{
"ImportPath": "github.com/bitrise-io/go-utils/command",
- "Rev": "e9b911a4cdf5eda62401973d0c299e7e42637315"
+ "Rev": "9c30a7825aa1064e423a0f1dba751fec990b07be"
},
{
"ImportPath": "github.com/bitrise-io/go-utils/errorutil",
- "Rev": "e9b911a4cdf5eda62401973d0c299e7e42637315"
+ "Rev": "9c30a7825aa1064e423a0f1dba751fec990b07be"
},
{
"ImportPath": "github.com/bitrise-io/go-utils/fileutil",
- "Rev": "e9b911a4cdf5eda62401973d0c299e7e42637315"
+ "Rev": "9c30a7825aa1064e423a0f1dba751fec990b07be"
},
{
"ImportPath": "github.com/bitrise-io/go-utils/log",
- "Rev": "e9b911a4cdf5eda62401973d0c299e7e42637315"
+ "Rev": "9c30a7825aa1064e423a0f1dba751fec990b07be"
},
{
"ImportPath": "github.com/bitrise-io/go-utils/pathutil",
- "Rev": "e9b911a4cdf5eda62401973d0c299e7e42637315"
+ "Rev": "9c30a7825aa1064e423a0f1dba751fec990b07be"
},
{
"ImportPath": "github.com/bitrise-tools/go-xcode/exportoptions",
- "Rev": "dfe3c2b59593ee83ef605fba21fa92501d1c68bf"
+ "Rev": "ab78c66cd596d02b8eff11b4c72de1f768bb93bb"
+ },
+ {
+ "ImportPath": "github.com/bitrise-tools/go-xcode/models",
+ "Rev": "ab78c66cd596d02b8eff11b4c72de1f768bb93bb"
+ },
+ {
+ "ImportPath": "github.com/bitrise-tools/go-xcode/plistutil",
+ "Rev": "ab78c66cd596d02b8eff11b4c72de1f768bb93bb"
},
{
"ImportPath": "github.com/bitrise-tools/go-xcode/provisioningprofile",
- "Rev": "dfe3c2b59593ee83ef605fba21fa92501d1c68bf"
+ "Rev": "ab78c66cd596d02b8eff11b4c72de1f768bb93bb"
+ },
+ {
+ "ImportPath": "github.com/bitrise-tools/go-xcode/utility",
+ "Rev": "ab78c66cd596d02b8eff11b4c72de1f768bb93bb"
},
{
"ImportPath": "github.com/bitrise-tools/go-xcode/xcarchive",
- "Rev": "dfe3c2b59593ee83ef605fba21fa92501d1c68bf"
+ "Rev": "ab78c66cd596d02b8eff11b4c72de1f768bb93bb"
},
{
"ImportPath": "github.com/bitrise-tools/go-xcode/xcodebuild",
- "Rev": "dfe3c2b59593ee83ef605fba21fa92501d1c68bf"
+ "Rev": "ab78c66cd596d02b8eff11b4c72de1f768bb93bb"
},
{
"ImportPath": "github.com/bitrise-tools/go-xcode/xcpretty",
- "Rev": "dfe3c2b59593ee83ef605fba21fa92501d1c68bf"
+ "Rev": "ab78c66cd596d02b8eff11b4c72de1f768bb93bb"
},
{
"ImportPath": "github.com/hashicorp/go-version",
@@ -61,6 +69,10 @@
{
"ImportPath": "github.com/kballard/go-shellquote",
"Rev": "d8ec1a69a250a17bb0e419c386eac1f3711dc142"
+ },
+ {
+ "ImportPath": "howett.net/plist",
+ "Rev": "2f847ea62b17703c861484a09f0e5841328a2cb9"
}
]
}
diff --git a/gows.yml b/gows.yml
new file mode 100644
index 00000000..9439d8ac
--- /dev/null
+++ b/gows.yml
@@ -0,0 +1 @@
+package_name: github.com/bitrise-io/steps-xcode-archive
diff --git a/main.go b/main.go
index c2d506ef..9410aa45 100644
--- a/main.go
+++ b/main.go
@@ -472,17 +472,18 @@ is available in the $BITRISE_XCODE_RAW_RESULT_TEXT_PATH environment variable`)
under the Products/Applications folder
*/
- embeddedProfilePth, err := xcarchive.EmbeddedMobileProvisionPth(tmpArchivePath)
+ embeddedProfilePth, err := xcarchive.FindEmbeddedMobileProvision(tmpArchivePath)
if err != nil {
fail("Failed to get embedded profile path, error: %s", err)
}
- provProfile, err := provisioningprofile.NewFromFile(embeddedProfilePth)
+ provProfilePlistData, err := provisioningprofile.NewPlistDataFromFile(embeddedProfilePth)
if err != nil {
fail("Failed to create provisioning profile model, error: %s", err)
}
- if provProfile.Name == nil {
+ name, found := provProfilePlistData.GetString("Name")
+ if !found {
fail("Profile name empty")
}
@@ -490,7 +491,7 @@ is available in the $BITRISE_XCODE_RAW_RESULT_TEXT_PATH environment variable`)
legacyExportCmd.SetExportFormat("ipa")
legacyExportCmd.SetArchivePath(tmpArchivePath)
legacyExportCmd.SetExportPath(ipaPath)
- legacyExportCmd.SetExportProvisioningProfileName(*provProfile.Name)
+ legacyExportCmd.SetExportProvisioningProfileName(name)
if configs.OutputTool == "xcpretty" {
xcprettyCmd := xcpretty.New(legacyExportCmd)
@@ -534,17 +535,17 @@ is available in the $BITRISE_XCODE_RAW_RESULT_TEXT_PATH environment variable`)
if configs.ExportMethod == "auto-detect" {
log.Printf("auto-detect export method, based on embedded profile")
- embeddedProfilePth, err := xcarchive.EmbeddedMobileProvisionPth(tmpArchivePath)
+ embeddedProfilePth, err := xcarchive.FindEmbeddedMobileProvision(tmpArchivePath)
if err != nil {
fail("Failed to get embedded profile path, error: %s", err)
}
- provProfile, err := provisioningprofile.NewFromFile(embeddedProfilePth)
+ provProfilePlistData, err := provisioningprofile.NewPlistDataFromFile(embeddedProfilePth)
if err != nil {
fail("Failed to create provisioning profile model, error: %s", err)
}
- method = provProfile.GetExportMethod()
+ method = provisioningprofile.GetExportMethod(provProfilePlistData)
log.Printf("detected export method: %s", method)
} else {
log.Printf("using export-method input: %s", configs.ExportMethod)
diff --git a/step.yml b/step.yml
index b34b1516..2ad1aea3 100644
--- a/step.yml
+++ b/step.yml
@@ -24,9 +24,6 @@ deps:
- name: xcode
brew:
- name: go
- apt_get:
- - name: golang
- bin_name: go
toolkit:
go:
package_name: github.com/bitrise-io/steps-xcode-archive
diff --git a/vendor/github.com/DHowett/go-plist/bplist.go b/vendor/github.com/DHowett/go-plist/bplist.go
deleted file mode 100644
index 45f07b42..00000000
--- a/vendor/github.com/DHowett/go-plist/bplist.go
+++ /dev/null
@@ -1,601 +0,0 @@
-package plist
-
-import (
- "bytes"
- "encoding/binary"
- "errors"
- "fmt"
- "hash/crc32"
- "io"
- "math"
- "runtime"
- "time"
- "unicode/utf16"
-)
-
-type bplistTrailer struct {
- Unused [5]uint8
- SortVersion uint8
- OffsetIntSize uint8
- ObjectRefSize uint8
- NumObjects uint64
- TopObject uint64
- OffsetTableOffset uint64
-}
-
-const (
- bpTagNull uint8 = 0x00
- bpTagBoolFalse = 0x08
- bpTagBoolTrue = 0x09
- bpTagInteger = 0x10
- bpTagReal = 0x20
- bpTagDate = 0x30
- bpTagData = 0x40
- bpTagASCIIString = 0x50
- bpTagUTF16String = 0x60
- bpTagUID = 0x80
- bpTagArray = 0xA0
- bpTagDictionary = 0xD0
-)
-
-type bplistGenerator struct {
- writer *countedWriter
- uniqmap map[interface{}]uint64
- objmap map[*plistValue]uint64
- objtable []*plistValue
- nobjects uint64
- trailer bplistTrailer
-}
-
-func (p *bplistGenerator) flattenPlistValue(pval *plistValue) {
- switch pval.kind {
- case String, Integer, Real:
- if _, ok := p.uniqmap[pval.value]; ok {
- return
- }
- p.uniqmap[pval.value] = p.nobjects
- case Date:
- k := pval.value.(time.Time).UnixNano()
- if _, ok := p.uniqmap[k]; ok {
- return
- }
- p.uniqmap[k] = p.nobjects
- case Data:
- // Data are uniqued by their checksums.
- // The wonderful difference between uint64 (which we use for numbers)
- // and uint32 makes this possible.
- // Todo: Look at calculating this only once and storing it somewhere;
- // crc32 is fairly quick, however.
- uniqkey := crc32.ChecksumIEEE(pval.value.([]byte))
- if _, ok := p.uniqmap[uniqkey]; ok {
- return
- }
- p.uniqmap[uniqkey] = p.nobjects
- }
-
- p.objtable = append(p.objtable, pval)
- p.objmap[pval] = p.nobjects
- p.nobjects++
-
- switch pval.kind {
- case Dictionary:
- dict := pval.value.(*dictionary)
- dict.populateArrays()
- for _, k := range dict.keys {
- p.flattenPlistValue(&plistValue{String, k})
- }
- for _, v := range dict.values {
- p.flattenPlistValue(v)
- }
- case Array:
- subvalues := pval.value.([]*plistValue)
- for _, v := range subvalues {
- p.flattenPlistValue(v)
- }
- }
-}
-
-func (p *bplistGenerator) indexForPlistValue(pval *plistValue) (uint64, bool) {
- var v uint64
- var ok bool
- switch pval.kind {
- case String, Integer, Real:
- v, ok = p.uniqmap[pval.value]
- case Date:
- v, ok = p.uniqmap[pval.value.(time.Time).UnixNano()]
- case Data:
- v, ok = p.uniqmap[crc32.ChecksumIEEE(pval.value.([]byte))]
- default:
- v, ok = p.objmap[pval]
- }
- return v, ok
-}
-
-func (p *bplistGenerator) generateDocument(rootpval *plistValue) {
- p.objtable = make([]*plistValue, 0, 15)
- p.uniqmap = make(map[interface{}]uint64)
- p.objmap = make(map[*plistValue]uint64)
- p.flattenPlistValue(rootpval)
-
- p.trailer.NumObjects = uint64(len(p.objtable))
- p.trailer.ObjectRefSize = uint8(minimumSizeForInt(p.trailer.NumObjects))
-
- p.writer.Write([]byte("bplist00"))
-
- offtable := make([]uint64, p.trailer.NumObjects)
- for i, pval := range p.objtable {
- offtable[i] = uint64(p.writer.BytesWritten())
- p.writePlistValue(pval)
- }
-
- p.trailer.OffsetIntSize = uint8(minimumSizeForInt(uint64(p.writer.BytesWritten())))
- p.trailer.TopObject = p.objmap[rootpval]
- p.trailer.OffsetTableOffset = uint64(p.writer.BytesWritten())
-
- for _, offset := range offtable {
- p.writeSizedInt(offset, int(p.trailer.OffsetIntSize))
- }
-
- binary.Write(p.writer, binary.BigEndian, p.trailer)
-}
-
-func (p *bplistGenerator) writePlistValue(pval *plistValue) {
- if pval == nil {
- return
- }
-
- switch pval.kind {
- case Dictionary:
- p.writeDictionaryTag(pval.value.(*dictionary))
- case Array:
- p.writeArrayTag(pval.value.([]*plistValue))
- case String:
- p.writeStringTag(pval.value.(string))
- case Integer:
- p.writeIntTag(pval.value.(signedInt).value)
- case Real:
- p.writeRealTag(pval.value.(sizedFloat).value, pval.value.(sizedFloat).bits)
- case Boolean:
- p.writeBoolTag(pval.value.(bool))
- case Data:
- p.writeDataTag(pval.value.([]byte))
- case Date:
- p.writeDateTag(pval.value.(time.Time))
- }
-}
-
-func minimumSizeForInt(n uint64) int {
- switch {
- case n <= uint64(0xff):
- return 1
- case n <= uint64(0xffff):
- return 2
- case n <= uint64(0xffffffff):
- return 4
- default:
- return 8
- }
- panic(errors.New("illegal integer size"))
-}
-
-func (p *bplistGenerator) writeSizedInt(n uint64, nbytes int) {
- var val interface{}
- switch nbytes {
- case 1:
- val = uint8(n)
- case 2:
- val = uint16(n)
- case 4:
- val = uint32(n)
- case 8:
- val = n
- default:
- panic(errors.New("illegal integer size"))
- }
- binary.Write(p.writer, binary.BigEndian, val)
-}
-
-func (p *bplistGenerator) writeBoolTag(v bool) {
- tag := uint8(bpTagBoolFalse)
- if v {
- tag = bpTagBoolTrue
- }
- binary.Write(p.writer, binary.BigEndian, tag)
-}
-
-func (p *bplistGenerator) writeIntTag(n uint64) {
- var tag uint8
- var val interface{}
- switch {
- case n <= uint64(0xff):
- val = uint8(n)
- tag = bpTagInteger | 0x0
- case n <= uint64(0xffff):
- val = uint16(n)
- tag = bpTagInteger | 0x1
- case n <= uint64(0xffffffff):
- val = uint32(n)
- tag = bpTagInteger | 0x2
- default:
- val = n
- tag = bpTagInteger | 0x3
- }
-
- binary.Write(p.writer, binary.BigEndian, tag)
- binary.Write(p.writer, binary.BigEndian, val)
-}
-
-func (p *bplistGenerator) writeRealTag(n float64, bits int) {
- var tag uint8 = bpTagReal | 0x3
- var val interface{} = n
- if bits == 32 {
- val = float32(n)
- tag = bpTagReal | 0x2
- }
-
- binary.Write(p.writer, binary.BigEndian, tag)
- binary.Write(p.writer, binary.BigEndian, val)
-}
-
-func (p *bplistGenerator) writeDateTag(t time.Time) {
- tag := uint8(bpTagDate) | 0x3
- val := float64(t.In(time.UTC).UnixNano()) / float64(time.Second)
- val -= 978307200 // Adjust to Apple Epoch
-
- binary.Write(p.writer, binary.BigEndian, tag)
- binary.Write(p.writer, binary.BigEndian, val)
-}
-
-func (p *bplistGenerator) writeCountedTag(tag uint8, count uint64) {
- marker := tag
- if count >= 0xF {
- marker |= 0xF
- } else {
- marker |= uint8(count)
- }
-
- binary.Write(p.writer, binary.BigEndian, marker)
-
- if count >= 0xF {
- p.writeIntTag(count)
- }
-}
-
-func (p *bplistGenerator) writeDataTag(data []byte) {
- p.writeCountedTag(bpTagData, uint64(len(data)))
- binary.Write(p.writer, binary.BigEndian, data)
-}
-
-func (p *bplistGenerator) writeStringTag(str string) {
- for _, r := range str {
- if r > 0xFF {
- utf16Runes := utf16.Encode([]rune(str))
- p.writeCountedTag(bpTagUTF16String, uint64(len(utf16Runes)))
- binary.Write(p.writer, binary.BigEndian, utf16Runes)
- return
- }
- }
-
- p.writeCountedTag(bpTagASCIIString, uint64(len(str)))
- binary.Write(p.writer, binary.BigEndian, []byte(str))
-}
-
-func (p *bplistGenerator) writeDictionaryTag(dict *dictionary) {
- p.writeCountedTag(bpTagDictionary, uint64(dict.count))
- vals := make([]uint64, dict.count*2)
- cnt := dict.count
- for i, k := range dict.keys {
- keyIdx, ok := p.uniqmap[k]
- if !ok {
- panic(errors.New("failed to find key " + k + " in object map during serialization"))
- }
- vals[i] = keyIdx
- }
- for i, v := range dict.values {
- objIdx, ok := p.indexForPlistValue(v)
- if !ok {
- panic(errors.New("failed to find value in object map during serialization"))
- }
- vals[i+cnt] = objIdx
- }
-
- for _, v := range vals {
- p.writeSizedInt(v, int(p.trailer.ObjectRefSize))
- }
-}
-
-func (p *bplistGenerator) writeArrayTag(arr []*plistValue) {
- p.writeCountedTag(bpTagArray, uint64(len(arr)))
- for _, v := range arr {
- objIdx, ok := p.indexForPlistValue(v)
- if !ok {
- panic(errors.New("failed to find value in object map during serialization"))
- }
-
- p.writeSizedInt(objIdx, int(p.trailer.ObjectRefSize))
- }
-}
-
-func (p *bplistGenerator) Indent(i string) {
- // There's nothing to indent.
-}
-
-func newBplistGenerator(w io.Writer) *bplistGenerator {
- return &bplistGenerator{
- writer: &countedWriter{Writer: mustWriter{w}},
- }
-}
-
-type bplistParser struct {
- reader io.ReadSeeker
- version int
- buf []byte
- objrefs map[uint64]*plistValue
- offtable []uint64
- trailer bplistTrailer
- trailerOffset int64
-}
-
-func (p *bplistParser) 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{"binary", r.(error)}
- }
- }
- }()
-
- magic := make([]byte, 6)
- ver := make([]byte, 2)
- p.reader.Seek(0, 0)
- p.reader.Read(magic)
- if !bytes.Equal(magic, []byte("bplist")) {
- panic(invalidPlistError{"binary", errors.New("mismatched magic")})
- }
-
- _, err := p.reader.Read(ver)
- if err != nil {
- panic(err)
- }
-
- p.version = int(mustParseInt(string(ver), 10, 0))
-
- if p.version > 1 {
- panic(fmt.Errorf("unexpected version %d", p.version))
- }
-
- p.objrefs = make(map[uint64]*plistValue)
- p.trailerOffset, err = p.reader.Seek(-32, 2)
- if err != nil && err != io.EOF {
- panic(err)
- }
-
- err = binary.Read(p.reader, binary.BigEndian, &p.trailer)
- if err != nil && err != io.EOF {
- panic(err)
- }
-
- if p.trailer.NumObjects > uint64(math.Pow(2, 8*float64(p.trailer.ObjectRefSize))) {
- panic(fmt.Errorf("binary property list contains more objects (%v) than its object ref size (%v bytes) can support", p.trailer.NumObjects, p.trailer.ObjectRefSize))
- }
-
- if p.trailer.TopObject >= p.trailer.NumObjects {
- panic(fmt.Errorf("top object index %v is out of range (only %v objects exist)", p.trailer.TopObject, p.trailer.NumObjects))
- }
- p.offtable = make([]uint64, p.trailer.NumObjects)
-
- // SEEK_SET
- _, err = p.reader.Seek(int64(p.trailer.OffsetTableOffset), 0)
- if err != nil && err != io.EOF {
- panic(err)
- }
-
- for i := uint64(0); i < p.trailer.NumObjects; i++ {
- off := p.readSizedInt(int(p.trailer.OffsetIntSize))
- if off >= uint64(p.trailerOffset) {
- panic(fmt.Errorf("object %v starts beyond end of plist trailer (%v vs %v)", i, off, p.trailerOffset))
- }
- p.offtable[i] = off
- }
-
- for _, off := range p.offtable {
- p.valueAtOffset(off)
- }
-
- pval = p.valueAtOffset(p.offtable[p.trailer.TopObject])
- return
-}
-
-func (p *bplistParser) readSizedInt(nbytes int) uint64 {
- switch nbytes {
- case 1:
- var val uint8
- binary.Read(p.reader, binary.BigEndian, &val)
- return uint64(val)
- case 2:
- var val uint16
- binary.Read(p.reader, binary.BigEndian, &val)
- return uint64(val)
- case 4:
- var val uint32
- binary.Read(p.reader, binary.BigEndian, &val)
- return uint64(val)
- case 8:
- var val uint64
- binary.Read(p.reader, binary.BigEndian, &val)
- return uint64(val)
- case 16:
- var high, low uint64
- binary.Read(p.reader, binary.BigEndian, &high)
- binary.Read(p.reader, binary.BigEndian, &low)
- // TODO: int128 support (!)
- return uint64(low)
- }
- panic(errors.New("illegal integer size"))
-}
-
-func (p *bplistParser) countForTag(tag uint8) uint64 {
- cnt := uint64(tag & 0x0F)
- if cnt == 0xF {
- var intTag uint8
- binary.Read(p.reader, binary.BigEndian, &intTag)
- cnt = p.readSizedInt(1 << (intTag & 0xF))
- }
- return cnt
-}
-
-func (p *bplistParser) valueAtOffset(off uint64) *plistValue {
- if pval, ok := p.objrefs[off]; ok {
- return pval
- }
- pval := p.parseTagAtOffset(int64(off))
- p.objrefs[off] = pval
- return pval
-}
-
-func (p *bplistParser) parseTagAtOffset(off int64) *plistValue {
- var tag uint8
- _, err := p.reader.Seek(off, 0)
- if err != nil {
- panic(err)
- }
- err = binary.Read(p.reader, binary.BigEndian, &tag)
- if err != nil {
- panic(err)
- }
-
- switch tag & 0xF0 {
- case bpTagNull:
- switch tag & 0x0F {
- case bpTagBoolTrue, bpTagBoolFalse:
- return &plistValue{Boolean, tag == bpTagBoolTrue}
- }
- return nil
- case bpTagInteger:
- val := p.readSizedInt(1 << (tag & 0xF))
- return &plistValue{Integer, signedInt{val, false}}
- case bpTagReal:
- nbytes := 1 << (tag & 0x0F)
- switch nbytes {
- case 4:
- var val float32
- binary.Read(p.reader, binary.BigEndian, &val)
- return &plistValue{Real, sizedFloat{float64(val), 32}}
- case 8:
- var val float64
- binary.Read(p.reader, binary.BigEndian, &val)
- return &plistValue{Real, sizedFloat{float64(val), 64}}
- }
- panic(errors.New("illegal float size"))
- case bpTagDate:
- var val float64
- binary.Read(p.reader, binary.BigEndian, &val)
-
- // Apple Epoch is 20110101000000Z
- // Adjust for UNIX Time
- val += 978307200
-
- sec, fsec := math.Modf(val)
- time := time.Unix(int64(sec), int64(fsec*float64(time.Second))).In(time.UTC)
- return &plistValue{Date, time}
- case bpTagData:
- cnt := p.countForTag(tag)
- if int64(cnt) > p.trailerOffset-int64(off) {
- panic(fmt.Errorf("data at %x longer than file (%v bytes, max is %v)", off, cnt, p.trailerOffset-int64(off)))
- }
-
- bytes := make([]byte, cnt)
- binary.Read(p.reader, binary.BigEndian, bytes)
- return &plistValue{Data, bytes}
- case bpTagASCIIString, bpTagUTF16String:
- cnt := p.countForTag(tag)
- if int64(cnt) > p.trailerOffset-int64(off) {
- panic(fmt.Errorf("string at %x longer than file (%v bytes, max is %v)", off, cnt, p.trailerOffset-int64(off)))
- }
-
- if tag&0xF0 == bpTagASCIIString {
- bytes := make([]byte, cnt)
- binary.Read(p.reader, binary.BigEndian, bytes)
- return &plistValue{String, string(bytes)}
- } else {
- bytes := make([]uint16, cnt)
- binary.Read(p.reader, binary.BigEndian, bytes)
- runes := utf16.Decode(bytes)
- return &plistValue{String, string(runes)}
- }
- case bpTagUID: // Somehow different than int: low half is nbytes - 1 instead of log2(nbytes)
- val := p.readSizedInt(int(tag&0xF) + 1)
- return &plistValue{Integer, signedInt{val, false}}
- case bpTagDictionary:
- cnt := p.countForTag(tag)
-
- subvalues := make(map[string]*plistValue)
- indices := make([]uint64, cnt*2)
- for i := uint64(0); i < cnt*2; i++ {
- idx := p.readSizedInt(int(p.trailer.ObjectRefSize))
-
- if idx >= p.trailer.NumObjects {
- panic(fmt.Errorf("dictionary contains invalid entry index %d (max %d)", idx, p.trailer.NumObjects))
- }
-
- indices[i] = idx
- }
- for i := uint64(0); i < cnt; i++ {
- keyOffset := p.offtable[indices[i]]
- valueOffset := p.offtable[indices[i+cnt]]
- if keyOffset == uint64(off) {
- panic(fmt.Errorf("dictionary contains self-referential key %x (index %d)", off, i))
- }
- if valueOffset == uint64(off) {
- panic(fmt.Errorf("dictionary contains self-referential value %x (index %d)", off, i))
- }
-
- kval := p.valueAtOffset(keyOffset)
- if kval == nil || kval.kind != String {
- panic(fmt.Errorf("dictionary contains non-string key at index %d", i))
- }
-
- key, ok := kval.value.(string)
- if !ok {
- panic(fmt.Errorf("string-type plist value contains non-string at index %d", i))
- }
- subvalues[key] = p.valueAtOffset(valueOffset)
- }
-
- return &plistValue{Dictionary, &dictionary{m: subvalues}}
- case bpTagArray:
- cnt := p.countForTag(tag)
-
- arr := make([]*plistValue, cnt)
- indices := make([]uint64, cnt)
- for i := uint64(0); i < cnt; i++ {
- idx := p.readSizedInt(int(p.trailer.ObjectRefSize))
-
- if idx >= p.trailer.NumObjects {
- panic(fmt.Errorf("array contains invalid entry index %d (max %d)", idx, p.trailer.NumObjects))
- }
-
- indices[i] = idx
- }
- for i := uint64(0); i < cnt; i++ {
- valueOffset := p.offtable[indices[i]]
- if valueOffset == uint64(off) {
- panic(fmt.Errorf("array contains self-referential value %x (index %d)", off, i))
- }
- arr[i] = p.valueAtOffset(valueOffset)
- }
-
- return &plistValue{Array, arr}
- }
- panic(fmt.Errorf("unexpected atom 0x%2.02x at offset %d", tag, off))
-}
-
-func newBplistParser(r io.ReadSeeker) *bplistParser {
- return &bplistParser{reader: r}
-}
diff --git a/vendor/github.com/DHowett/go-plist/plist.go b/vendor/github.com/DHowett/go-plist/plist.go
deleted file mode 100644
index 17201fda..00000000
--- a/vendor/github.com/DHowett/go-plist/plist.go
+++ /dev/null
@@ -1,141 +0,0 @@
-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
-}
diff --git a/vendor/github.com/DHowett/go-plist/text.go b/vendor/github.com/DHowett/go-plist/text.go
deleted file mode 100644
index 60cb0db0..00000000
--- a/vendor/github.com/DHowett/go-plist/text.go
+++ /dev/null
@@ -1,569 +0,0 @@
-package plist
-
-import (
- "bufio"
- "encoding/hex"
- "errors"
- "io"
- "runtime"
- "strconv"
- "strings"
- "time"
-)
-
-type textPlistGenerator struct {
- writer io.Writer
- format int
-
- quotableTable *[4]uint64
-
- indent string
- depth int
-
- dictKvDelimiter, dictEntryDelimiter, arrayDelimiter []byte
-}
-
-var (
- textPlistTimeLayout = "2006-01-02 15:04:05 -0700"
- padding = "0000"
-)
-
-func (p *textPlistGenerator) generateDocument(pval *plistValue) {
- p.writePlistValue(pval)
-}
-
-func (p *textPlistGenerator) plistQuotedString(str string) string {
- if str == "" {
- return `""`
- }
- s := ""
- quot := false
- for _, r := range str {
- if r > 0xFF {
- quot = true
- s += `\U`
- us := strconv.FormatInt(int64(r), 16)
- s += padding[len(us):]
- s += us
- } else if r > 0x7F {
- quot = true
- s += `\`
- us := strconv.FormatInt(int64(r), 8)
- s += padding[1+len(us):]
- s += us
- } else {
- c := uint8(r)
- if (*p.quotableTable)[c/64]&(1<<(c%64)) > 0 {
- quot = true
- }
-
- switch c {
- case '\a':
- s += `\a`
- case '\b':
- s += `\b`
- case '\v':
- s += `\v`
- case '\f':
- s += `\f`
- case '\\':
- s += `\\`
- case '"':
- s += `\"`
- case '\t', '\r', '\n':
- fallthrough
- default:
- s += string(c)
- }
- }
- }
- if quot {
- s = `"` + s + `"`
- }
- return s
-}
-
-func (p *textPlistGenerator) deltaIndent(depthDelta int) {
- if depthDelta < 0 {
- p.depth--
- } else if depthDelta > 0 {
- p.depth++
- }
-}
-
-func (p *textPlistGenerator) writeIndent() {
- if len(p.indent) == 0 {
- return
- }
- if len(p.indent) > 0 {
- p.writer.Write([]byte("\n"))
- for i := 0; i < p.depth; i++ {
- io.WriteString(p.writer, p.indent)
- }
- }
-}
-
-func (p *textPlistGenerator) writePlistValue(pval *plistValue) {
- if pval == nil {
- return
- }
-
- switch pval.kind {
- case Dictionary:
- p.writer.Write([]byte(`{`))
- p.deltaIndent(1)
- dict := pval.value.(*dictionary)
- dict.populateArrays()
- for i, k := range dict.keys {
- p.writeIndent()
- io.WriteString(p.writer, p.plistQuotedString(k))
- p.writer.Write(p.dictKvDelimiter)
- p.writePlistValue(dict.values[i])
- p.writer.Write(p.dictEntryDelimiter)
- }
- p.deltaIndent(-1)
- p.writeIndent()
- p.writer.Write([]byte(`}`))
- case Array:
- p.writer.Write([]byte(`(`))
- p.deltaIndent(1)
- values := pval.value.([]*plistValue)
- for _, v := range values {
- p.writeIndent()
- p.writePlistValue(v)
- p.writer.Write(p.arrayDelimiter)
- }
- p.deltaIndent(-1)
- p.writeIndent()
- p.writer.Write([]byte(`)`))
- case String:
- io.WriteString(p.writer, p.plistQuotedString(pval.value.(string)))
- case Integer:
- if p.format == GNUStepFormat {
- p.writer.Write([]byte(`<*I`))
- }
- if pval.value.(signedInt).signed {
- io.WriteString(p.writer, strconv.FormatInt(int64(pval.value.(signedInt).value), 10))
- } else {
- io.WriteString(p.writer, strconv.FormatUint(pval.value.(signedInt).value, 10))
- }
- if p.format == GNUStepFormat {
- p.writer.Write([]byte(`>`))
- }
- case Real:
- if p.format == GNUStepFormat {
- p.writer.Write([]byte(`<*R`))
- }
- io.WriteString(p.writer, strconv.FormatFloat(pval.value.(sizedFloat).value, 'g', -1, 64))
- if p.format == GNUStepFormat {
- p.writer.Write([]byte(`>`))
- }
- case Boolean:
- b := pval.value.(bool)
- if p.format == GNUStepFormat {
- if b {
- p.writer.Write([]byte(`<*BY>`))
- } else {
- p.writer.Write([]byte(`<*BN>`))
- }
- } else {
- if b {
- p.writer.Write([]byte(`1`))
- } else {
- p.writer.Write([]byte(`0`))
- }
- }
- case Data:
- b := pval.value.([]byte)
- var hexencoded [9]byte
- var l int
- var asc = 9
- hexencoded[8] = ' '
-
- p.writer.Write([]byte(`<`))
- for i := 0; i < len(b); i += 4 {
- l = i + 4
- if l >= len(b) {
- l = len(b)
- // We no longer need the space - or the rest of the buffer.
- // (we used >= above to get this part without another conditional :P)
- asc = (l - i) * 2
- }
- // Fill the buffer (only up to 8 characters, to preserve the space we implicitly include
- // at the end of every encode)
- hex.Encode(hexencoded[:8], b[i:l])
- io.WriteString(p.writer, string(hexencoded[:asc]))
- }
- p.writer.Write([]byte(`>`))
- case Date:
- if p.format == GNUStepFormat {
- p.writer.Write([]byte(`<*D`))
- io.WriteString(p.writer, pval.value.(time.Time).In(time.UTC).Format(textPlistTimeLayout))
- p.writer.Write([]byte(`>`))
- } else {
- io.WriteString(p.writer, p.plistQuotedString(pval.value.(time.Time).In(time.UTC).Format(textPlistTimeLayout)))
- }
- }
-}
-
-func (p *textPlistGenerator) Indent(i string) {
- p.indent = i
- if i == "" {
- p.dictKvDelimiter = []byte(`=`)
- } else {
- // For pretty-printing
- p.dictKvDelimiter = []byte(` = `)
- }
-}
-
-func newTextPlistGenerator(w io.Writer, format int) *textPlistGenerator {
- table := &osQuotable
- if format == GNUStepFormat {
- table = &gsQuotable
- }
- return &textPlistGenerator{
- writer: mustWriter{w},
- format: format,
- quotableTable: table,
- dictKvDelimiter: []byte(`=`),
- arrayDelimiter: []byte(`,`),
- dictEntryDelimiter: []byte(`;`),
- }
-}
-
-type byteReader interface {
- io.Reader
- io.ByteScanner
- Peek(n int) ([]byte, error)
- ReadBytes(delim byte) ([]byte, error)
-}
-
-type textPlistParser struct {
- reader byteReader
- whitespaceReplacer *strings.Replacer
- format int
-}
-
-func (p *textPlistParser) 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{"text", r.(error)}
- }
- }
- }()
- pval = p.parsePlistValue()
- return
-}
-
-func (p *textPlistParser) chugWhitespace() {
-ws:
- for {
- c, err := p.reader.ReadByte()
- if err != nil && err != io.EOF {
- panic(err)
- }
- if whitespace[c/64]&(1<<(c%64)) == 0 {
- if c == '/' && err != io.EOF {
- // A / at the end of the file is not the begining of a comment.
- cs, err := p.reader.Peek(1)
- if err != nil && err != io.EOF {
- panic(err)
- }
- c = cs[0]
- switch c {
- case '/':
- for {
- c, err = p.reader.ReadByte()
- if err != nil && err != io.EOF {
- panic(err)
- } else if err == io.EOF {
- break
- }
- // TODO: UTF-8
- if c == '\n' || c == '\r' {
- break
- }
- }
- case '*':
- // Peek returned a value here, so it is safe to read.
- _, _ = p.reader.ReadByte()
- star := false
- for {
- c, err = p.reader.ReadByte()
- if err != nil {
- panic(err)
- }
- if c == '*' {
- star = true
- } else if c == '/' && star {
- break
- } else {
- star = false
- }
- }
- default:
- p.reader.UnreadByte() // Not the beginning of a // or /* comment
- break ws
- }
- continue
- }
- p.reader.UnreadByte()
- break
- }
- }
-}
-
-func (p *textPlistParser) parseQuotedString() *plistValue {
- escaping := false
- s := ""
- for {
- byt, err := p.reader.ReadByte()
- // EOF here is an error: we're inside a quoted string!
- if err != nil {
- panic(err)
- }
- c := rune(byt)
- if !escaping {
- if c == '"' {
- break
- } else if c == '\\' {
- escaping = true
- continue
- }
- } else {
- escaping = false
- // Everything that is not listed here passes through unharmed.
- switch c {
- case 'a':
- c = '\a'
- case 'b':
- c = '\b'
- case 'v':
- c = '\v'
- case 'f':
- c = '\f'
- case 't':
- c = '\t'
- case 'r':
- c = '\r'
- case 'n':
- c = '\n'
- case 'x', 'u', 'U': // hex and unicode
- l := 4
- if c == 'x' {
- l = 2
- }
- hex := make([]byte, l)
- p.reader.Read(hex)
- newc := mustParseInt(string(hex), 16, 16)
- c = rune(newc)
- case '0', '1', '2', '3', '4', '5', '6', '7': // octal!
- oct := make([]byte, 3)
- oct[0] = uint8(c)
- p.reader.Read(oct[1:])
- newc := mustParseInt(string(oct), 8, 16)
- c = rune(newc)
- }
- }
- s += string(c)
- }
- return &plistValue{String, s}
-}
-
-func (p *textPlistParser) parseUnquotedString() *plistValue {
- s := ""
- for {
- c, err := p.reader.ReadByte()
- if err != nil {
- if err == io.EOF {
- break
- }
- panic(err)
- }
- // if we encounter a character that must be quoted, we're done.
- // the GNUStep quote table is more lax here, so we use it instead of the OpenStep one.
- if gsQuotable[c/64]&(1<<(c%64)) > 0 {
- p.reader.UnreadByte()
- break
- }
- s += string(c)
- }
- return &plistValue{String, s}
-}
-
-func (p *textPlistParser) parseDictionary() *plistValue {
- var keypv *plistValue
- subval := make(map[string]*plistValue)
- for {
- p.chugWhitespace()
-
- c, err := p.reader.ReadByte()
- // EOF here is an error: we're inside a dictionary!
- if err != nil {
- panic(err)
- }
-
- if c == '}' {
- break
- } else if c == '"' {
- keypv = p.parseQuotedString()
- } else {
- p.reader.UnreadByte() // Whoops, ate part of the string
- keypv = p.parseUnquotedString()
- }
- if keypv == nil {
- // TODO better error
- panic(errors.New("missing dictionary key"))
- }
-
- p.chugWhitespace()
- c, err = p.reader.ReadByte()
- if err != nil {
- panic(err)
- }
-
- if c != '=' {
- panic(errors.New("missing = in dictionary"))
- }
-
- // whitespace is guzzled within
- val := p.parsePlistValue()
-
- p.chugWhitespace()
- c, err = p.reader.ReadByte()
- if err != nil {
- panic(err)
- }
-
- if c != ';' {
- panic(errors.New("missing ; in dictionary"))
- }
-
- subval[keypv.value.(string)] = val
- }
- return &plistValue{Dictionary, &dictionary{m: subval}}
-}
-
-func (p *textPlistParser) parseArray() *plistValue {
- subval := make([]*plistValue, 0, 10)
- for {
- c, err := p.reader.ReadByte()
- // EOF here is an error: we're inside an array!
- if err != nil {
- panic(err)
- }
-
- if c == ')' {
- break
- } else if c == ',' {
- continue
- }
-
- p.reader.UnreadByte()
- pval := p.parsePlistValue()
- if pval.kind == String && pval.value.(string) == "" {
- continue
- }
- subval = append(subval, pval)
- }
- return &plistValue{Array, subval}
-}
-
-func (p *textPlistParser) parseGNUStepValue(v []byte) *plistValue {
- if len(v) < 3 {
- panic(errors.New("invalid GNUStep extended value"))
- }
- typ := v[1]
- v = v[2:]
- switch typ {
- case 'I':
- if v[0] == '-' {
- n := mustParseInt(string(v), 10, 64)
- return &plistValue{Integer, signedInt{uint64(n), true}}
- } else {
- n := mustParseUint(string(v), 10, 64)
- return &plistValue{Integer, signedInt{n, false}}
- }
- case 'R':
- n := mustParseFloat(string(v), 64)
- return &plistValue{Real, sizedFloat{n, 64}}
- case 'B':
- b := v[0] == 'Y'
- return &plistValue{Boolean, b}
- case 'D':
- t, err := time.Parse(textPlistTimeLayout, string(v))
- if err != nil {
- panic(err)
- }
-
- return &plistValue{Date, t.In(time.UTC)}
- }
- panic(errors.New("invalid GNUStep type " + string(typ)))
- return nil
-}
-
-func (p *textPlistParser) parsePlistValue() *plistValue {
- for {
- p.chugWhitespace()
-
- c, err := p.reader.ReadByte()
- if err != nil && err != io.EOF {
- panic(err)
- }
- switch c {
- case '<':
- bytes, err := p.reader.ReadBytes('>')
- if err != nil {
- panic(err)
- }
- bytes = bytes[:len(bytes)-1]
-
- if len(bytes) == 0 {
- panic(errors.New("invalid empty angle-bracketed element"))
- }
-
- if bytes[0] == '*' {
- p.format = GNUStepFormat
- return p.parseGNUStepValue(bytes)
- } else {
- s := p.whitespaceReplacer.Replace(string(bytes))
- data, err := hex.DecodeString(s)
- if err != nil {
- panic(err)
- }
- return &plistValue{Data, data}
- }
- case '"':
- return p.parseQuotedString()
- case '{':
- return p.parseDictionary()
- case '(':
- return p.parseArray()
- default:
- p.reader.UnreadByte() // Place back in buffer for parseUnquotedString
- return p.parseUnquotedString()
- }
- }
- return nil
-}
-
-func newTextPlistParser(r io.Reader) *textPlistParser {
- var reader byteReader
- if rd, ok := r.(byteReader); ok {
- reader = rd
- } else {
- reader = bufio.NewReader(r)
- }
- return &textPlistParser{
- reader: reader,
- whitespaceReplacer: strings.NewReplacer("\t", "", "\n", "", " ", "", "\r", ""),
- format: OpenStepFormat,
- }
-}
diff --git a/vendor/github.com/DHowett/go-plist/unmarshal.go b/vendor/github.com/DHowett/go-plist/unmarshal.go
deleted file mode 100644
index fc50ed4a..00000000
--- a/vendor/github.com/DHowett/go-plist/unmarshal.go
+++ /dev/null
@@ -1,276 +0,0 @@
-package plist
-
-import (
- "encoding"
- "fmt"
- "reflect"
- "time"
-)
-
-type incompatibleDecodeTypeError struct {
- typ reflect.Type
- pKind plistKind
-}
-
-func (u *incompatibleDecodeTypeError) Error() string {
- return fmt.Sprintf("plist: type mismatch: tried to decode %v into value of type %v", plistKindNames[u.pKind], u.typ)
-}
-
-var (
- textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
-)
-
-func isEmptyInterface(v reflect.Value) bool {
- return v.Kind() == reflect.Interface && v.NumMethod() == 0
-}
-
-func (p *Decoder) unmarshalTextInterface(pval *plistValue, unmarshalable encoding.TextUnmarshaler) {
- err := unmarshalable.UnmarshalText([]byte(pval.value.(string)))
- if err != nil {
- panic(err)
- }
-}
-
-func (p *Decoder) unmarshalTime(pval *plistValue, val reflect.Value) {
- val.Set(reflect.ValueOf(pval.value.(time.Time)))
-}
-
-func (p *Decoder) unmarshalLaxString(s string, val reflect.Value) {
- switch val.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- i := mustParseInt(s, 10, 64)
- val.SetInt(i)
- return
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- i := mustParseUint(s, 10, 64)
- val.SetUint(i)
- return
- case reflect.Float32, reflect.Float64:
- f := mustParseFloat(s, 64)
- val.SetFloat(f)
- return
- case reflect.Bool:
- b := mustParseBool(s)
- val.SetBool(b)
- return
- case reflect.Struct:
- if val.Type() == timeType {
- t, err := time.Parse(textPlistTimeLayout, s)
- if err != nil {
- panic(err)
- }
- val.Set(reflect.ValueOf(t.In(time.UTC)))
- return
- }
- fallthrough
- default:
- panic(&incompatibleDecodeTypeError{val.Type(), String})
- }
-}
-
-func (p *Decoder) unmarshal(pval *plistValue, val reflect.Value) {
- if pval == nil {
- return
- }
-
- if val.Kind() == reflect.Ptr {
- if val.IsNil() {
- val.Set(reflect.New(val.Type().Elem()))
- }
- val = val.Elem()
- }
-
- if isEmptyInterface(val) {
- v := p.valueInterface(pval)
- val.Set(reflect.ValueOf(v))
- return
- }
-
- incompatibleTypeError := &incompatibleDecodeTypeError{val.Type(), pval.kind}
-
- // time.Time implements TextMarshaler, but we need to parse it as RFC3339
- if pval.kind == Date {
- if val.Type() == timeType {
- p.unmarshalTime(pval, val)
- return
- }
- panic(incompatibleTypeError)
- }
-
- if val.CanInterface() && val.Type().Implements(textUnmarshalerType) && val.Type() != timeType {
- p.unmarshalTextInterface(pval, val.Interface().(encoding.TextUnmarshaler))
- return
- }
-
- if val.CanAddr() {
- pv := val.Addr()
- if pv.CanInterface() && pv.Type().Implements(textUnmarshalerType) && val.Type() != timeType {
- p.unmarshalTextInterface(pval, pv.Interface().(encoding.TextUnmarshaler))
- return
- }
- }
-
- typ := val.Type()
-
- switch pval.kind {
- case String:
- if val.Kind() == reflect.String {
- val.SetString(pval.value.(string))
- return
- }
- if p.lax {
- p.unmarshalLaxString(pval.value.(string), val)
- return
- }
-
- panic(incompatibleTypeError)
- case Integer:
- switch val.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- val.SetInt(int64(pval.value.(signedInt).value))
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- val.SetUint(pval.value.(signedInt).value)
- default:
- panic(incompatibleTypeError)
- }
- case Real:
- if val.Kind() == reflect.Float32 || val.Kind() == reflect.Float64 {
- val.SetFloat(pval.value.(sizedFloat).value)
- } else {
- panic(incompatibleTypeError)
- }
- case Boolean:
- if val.Kind() == reflect.Bool {
- val.SetBool(pval.value.(bool))
- } else {
- panic(incompatibleTypeError)
- }
- case Data:
- if val.Kind() == reflect.Slice && typ.Elem().Kind() == reflect.Uint8 {
- val.SetBytes(pval.value.([]byte))
- } else {
- panic(incompatibleTypeError)
- }
- case Array:
- p.unmarshalArray(pval, val)
- case Dictionary:
- p.unmarshalDictionary(pval, val)
- }
-}
-
-func (p *Decoder) unmarshalArray(pval *plistValue, val reflect.Value) {
- subvalues := pval.value.([]*plistValue)
-
- var n int
- if val.Kind() == reflect.Slice {
- // Slice of element values.
- // Grow slice.
- cnt := len(subvalues) + val.Len()
- if cnt >= val.Cap() {
- ncap := 2 * cnt
- if ncap < 4 {
- ncap = 4
- }
- new := reflect.MakeSlice(val.Type(), val.Len(), ncap)
- reflect.Copy(new, val)
- val.Set(new)
- }
- n = val.Len()
- val.SetLen(cnt)
- } else if val.Kind() == reflect.Array {
- if len(subvalues) > val.Cap() {
- panic(fmt.Errorf("plist: attempted to unmarshal %d values into an array of size %d", len(subvalues), val.Cap()))
- }
- } else {
- panic(&incompatibleDecodeTypeError{val.Type(), pval.kind})
- }
-
- // Recur to read element into slice.
- for _, sval := range subvalues {
- p.unmarshal(sval, val.Index(n))
- n++
- }
- return
-}
-
-func (p *Decoder) unmarshalDictionary(pval *plistValue, val reflect.Value) {
- typ := val.Type()
- switch val.Kind() {
- case reflect.Struct:
- tinfo, err := getTypeInfo(typ)
- if err != nil {
- panic(err)
- }
-
- subvalues := pval.value.(*dictionary).m
- for _, finfo := range tinfo.fields {
- p.unmarshal(subvalues[finfo.name], finfo.value(val))
- }
- case reflect.Map:
- if val.IsNil() {
- val.Set(reflect.MakeMap(typ))
- }
-
- subvalues := pval.value.(*dictionary).m
- for k, sval := range subvalues {
- keyv := reflect.ValueOf(k).Convert(typ.Key())
- mapElem := val.MapIndex(keyv)
- if !mapElem.IsValid() {
- mapElem = reflect.New(typ.Elem()).Elem()
- }
-
- p.unmarshal(sval, mapElem)
- val.SetMapIndex(keyv, mapElem)
- }
- default:
- panic(&incompatibleDecodeTypeError{typ, pval.kind})
- }
-}
-
-/* *Interface is modelled after encoding/json */
-func (p *Decoder) valueInterface(pval *plistValue) interface{} {
- switch pval.kind {
- case String:
- return pval.value.(string)
- case Integer:
- if pval.value.(signedInt).signed {
- return int64(pval.value.(signedInt).value)
- }
- return pval.value.(signedInt).value
- case Real:
- bits := pval.value.(sizedFloat).bits
- switch bits {
- case 32:
- return float32(pval.value.(sizedFloat).value)
- case 64:
- return pval.value.(sizedFloat).value
- }
- case Boolean:
- return pval.value.(bool)
- case Array:
- return p.arrayInterface(pval.value.([]*plistValue))
- case Dictionary:
- return p.dictionaryInterface(pval.value.(*dictionary))
- case Data:
- return pval.value.([]byte)
- case Date:
- return pval.value.(time.Time)
- }
- return nil
-}
-
-func (p *Decoder) arrayInterface(subvalues []*plistValue) []interface{} {
- out := make([]interface{}, len(subvalues))
- for i, subv := range subvalues {
- out[i] = p.valueInterface(subv)
- }
- return out
-}
-
-func (p *Decoder) dictionaryInterface(dict *dictionary) map[string]interface{} {
- out := make(map[string]interface{})
- for k, subv := range dict.m {
- out[k] = p.valueInterface(subv)
- }
- return out
-}
diff --git a/vendor/github.com/bitrise-io/go-utils/command/command.go b/vendor/github.com/bitrise-io/go-utils/command/command.go
index 040dbaf9..4cd005a3 100644
--- a/vendor/github.com/bitrise-io/go-utils/command/command.go
+++ b/vendor/github.com/bitrise-io/go-utils/command/command.go
@@ -32,15 +32,20 @@ func NewWithStandardOuts(name string, args ...string) *Model {
return New(name, args...).SetStdout(os.Stdout).SetStderr(os.Stderr)
}
-// NewFromSlice ...
-func NewFromSlice(slice ...string) (*Model, error) {
- if len(slice) == 0 {
+// NewWithParams ...
+func NewWithParams(params ...string) (*Model, error) {
+ if len(params) == 0 {
return nil, errors.New("no command provided")
- } else if len(slice) == 1 {
- return New(slice[0]), nil
+ } else if len(params) == 1 {
+ return New(params[0]), nil
}
- return New(slice[0], slice[1:]...), nil
+ return New(params[0], params[1:]...), nil
+}
+
+// NewFromSlice ...
+func NewFromSlice(slice []string) (*Model, error) {
+ return NewWithParams(slice...)
}
// NewWithCmd ...
diff --git a/vendor/github.com/bitrise-io/go-utils/command/git.go b/vendor/github.com/bitrise-io/go-utils/command/git.go
deleted file mode 100644
index 52f3dacf..00000000
--- a/vendor/github.com/bitrise-io/go-utils/command/git.go
+++ /dev/null
@@ -1,204 +0,0 @@
-package command
-
-import (
- "errors"
- "fmt"
- "log"
- "os/exec"
- "strings"
-
- "github.com/bitrise-io/go-utils/pathutil"
-)
-
-// GitClone ...
-func GitClone(uri, pth string) (err error) {
- if uri == "" {
- return errors.New("Git Clone 'uri' missing")
- }
- if pth == "" {
- return errors.New("Git Clone 'pth' missing")
- }
- if err = RunCommand("git", "clone", "--recursive", uri, pth); err != nil {
- log.Printf(" [!] Failed to git clone from (%s) to (%s)", uri, pth)
- return
- }
- return
-}
-
-// GitCloneTagOrBranch ...
-func GitCloneTagOrBranch(uri, pth, tagOrBranch string) error {
- if uri == "" {
- return errors.New("Git Clone 'uri' missing")
- }
- if pth == "" {
- return errors.New("Git Clone 'path' missing")
- }
- if tagOrBranch == "" {
- return errors.New("Git Clone 'tag or branch' missing")
- }
- return RunCommand("git", "clone", "--recursive", "--branch", tagOrBranch, uri, pth)
-}
-
-// GitCloneTag ...
-func GitCloneTag(uri, pth, tag string) error {
- if uri == "" {
- return errors.New("Git Clone 'uri' missing")
- }
- if pth == "" {
- return errors.New("Git Clone 'path' missing")
- }
- if tag == "" {
- return errors.New("Git Clone 'tag or branch' missing")
- }
- if err := RunCommand("git", "clone", "--recursive", "--branch", tag, uri, pth); err != nil {
- return fmt.Errorf("Git clone failed, err: %s", err)
- }
-
- out, err := RunCommandInDirAndReturnCombinedStdoutAndStderr(pth, "git", "branch")
- if err != nil {
- return fmt.Errorf("Failed to get git branches, err: %s", err)
- }
-
- if out != "* (no branch)" {
- return fmt.Errorf("Current HEAD is not detached head, current branch should be: '* (no branch)', got: %s", out)
- }
- return nil
-}
-
-// GitCloneTagOrBranchAndValidateCommitHash ...
-func GitCloneTagOrBranchAndValidateCommitHash(uri, pth, version, commithash string) (err error) {
- if uri == "" {
- return errors.New("Git Clone 'uri' missing")
- }
- if pth == "" {
- return errors.New("Git Clone 'pth' missing")
- }
- if version == "" {
- return errors.New("Git Clone 'version' missing")
- }
- if commithash == "" {
- return errors.New("Git Clone 'commithash' missing")
- }
- if err = RunCommand("git", "clone", "--recursive", uri, pth, "--branch", version); err != nil {
- return
- }
-
- // cleanup
- defer func() {
- if err != nil {
- if err := RemoveDir(pth); err != nil {
- log.Printf(" [!] Failed to cleanup path (%s) error: (%v) ", pth, err)
- }
- }
- }()
-
- latestCommit, err := GitGetLatestCommitHashOnHead(pth)
- if err != nil {
- return
- }
- if commithash != latestCommit {
- return fmt.Errorf("Commit hash doesn't match the one specified for the version tag. (version tag: %s) (expected commit hash: %s) (got: %s)", version, latestCommit, commithash)
- }
-
- return
-}
-
-// GitPull ...
-func GitPull(pth string) error {
- err := RunCommandInDir(pth, "git", "pull")
- if err != nil {
- log.Printf(" [!] Git pull failed, error (%v)", err)
- return err
- }
- return nil
-}
-
-// GitUpdate ...
-func GitUpdate(git, pth string) error {
- if exists, err := pathutil.IsPathExists(pth); err != nil {
- return err
- } else if !exists {
- fmt.Println("Git path does not exist, do clone")
- return GitClone(git, pth)
- }
-
- fmt.Println("Git path exist, do pull")
- return GitPull(pth)
-}
-
-// GitCheckout ...
-func GitCheckout(dir, branchOrTag string) error {
- if branchOrTag == "" {
- return errors.New("Git Clone 'branchOrTag' missing")
- }
- return RunCommandInDir(dir, "git", "checkout", branchOrTag)
-}
-
-// GitCreateAndCheckoutBranch ...
-func GitCreateAndCheckoutBranch(repoPath, branch string) error {
- if branch == "" {
- return errors.New("Git checkout 'branch' missing")
- }
- return RunCommandInDir(repoPath, "git", "checkout", "-b", branch)
-}
-
-// GitAddFile ...
-func GitAddFile(repoPath, filePath string) error {
- if filePath == "" {
- return errors.New("Git add 'file' missing")
- }
- return RunCommandInDir(repoPath, "git", "add", filePath)
-}
-
-// GitPushToOrigin ...
-func GitPushToOrigin(repoPath, branch string) error {
- if branch == "" {
- return errors.New("Git push 'branch' missing")
- }
- return RunCommandInDir(repoPath, "git", "push", "-u", "origin", branch)
-}
-
-// GitCheckIsNoChanges ...
-func GitCheckIsNoChanges(repoPath string) error {
- out, err := RunCommandInDirAndReturnCombinedStdoutAndStderr(repoPath, "git", "status", "--porcelain")
- if err != nil {
- log.Println(" [!] Failed to git check changes:", out)
- return err
- }
- if out != "" {
- return errors.New("Uncommited changes: " + out)
- }
- return nil
-}
-
-// GitCommit ...
-func GitCommit(repoPath string, message string) error {
- if message == "" {
- return errors.New("Git commit 'message' missing")
- }
- return RunCommandInDir(repoPath, "git", "commit", "-m", message)
-}
-
-// GitGetLatestCommitHashOnHead ...
-func GitGetLatestCommitHashOnHead(pth string) (string, error) {
- cmd := exec.Command("git", "rev-parse", "HEAD")
- cmd.Dir = pth
- bytes, err := cmd.CombinedOutput()
- cmdOutput := string(bytes)
- if err != nil {
- log.Printf(" [!] Output: %s", cmdOutput)
- }
- return strings.TrimSpace(cmdOutput), err
-}
-
-// GitGetCommitHashOfHEAD ...
-func GitGetCommitHashOfHEAD(pth string) (string, error) {
- cmd := exec.Command("git", "rev-parse", "HEAD")
- cmd.Dir = pth
- bytes, err := cmd.CombinedOutput()
- cmdOutput := string(bytes)
- if err != nil {
- log.Printf(" [!] Output: %s", cmdOutput)
- }
- return strings.TrimSpace(cmdOutput), err
-}
diff --git a/vendor/github.com/bitrise-io/go-utils/pathutil/pathutil.go b/vendor/github.com/bitrise-io/go-utils/pathutil/pathutil.go
index a0b08661..4e31d3cd 100644
--- a/vendor/github.com/bitrise-io/go-utils/pathutil/pathutil.go
+++ b/vendor/github.com/bitrise-io/go-utils/pathutil/pathutil.go
@@ -9,6 +9,32 @@ import (
"strings"
)
+// RevokableChangeDir ...
+func RevokableChangeDir(dir string) (func() error, error) {
+ origDir, err := CurrentWorkingDirectoryAbsolutePath()
+ if err != nil {
+ return nil, err
+ }
+
+ revokeFn := func() error {
+ return os.Chdir(origDir)
+ }
+
+ return revokeFn, os.Chdir(dir)
+}
+
+// ChangeDirForFunction ...
+func ChangeDirForFunction(dir string, fn func()) error {
+ revokeFn, err := RevokableChangeDir(dir)
+ if err != nil {
+ return err
+ }
+
+ fn()
+
+ return revokeFn()
+}
+
// IsRelativePath ...
func IsRelativePath(pth string) bool {
if strings.HasPrefix(pth, "./") {
diff --git a/vendor/github.com/bitrise-tools/go-xcode/exportoptions/appstore_options.go b/vendor/github.com/bitrise-tools/go-xcode/exportoptions/appstore_options.go
index 0e90cad0..3be1c908 100644
--- a/vendor/github.com/bitrise-tools/go-xcode/exportoptions/appstore_options.go
+++ b/vendor/github.com/bitrise-tools/go-xcode/exportoptions/appstore_options.go
@@ -3,7 +3,7 @@ package exportoptions
import (
"fmt"
- plist "github.com/DHowett/go-plist"
+ "howett.net/plist"
)
// AppStoreOptionsModel ...
diff --git a/vendor/github.com/bitrise-tools/go-xcode/exportoptions/exportoptions.go b/vendor/github.com/bitrise-tools/go-xcode/exportoptions/exportoptions.go
index d2550a94..7e0cdf90 100644
--- a/vendor/github.com/bitrise-tools/go-xcode/exportoptions/exportoptions.go
+++ b/vendor/github.com/bitrise-tools/go-xcode/exportoptions/exportoptions.go
@@ -4,9 +4,9 @@ import (
"fmt"
"path/filepath"
- plist "github.com/DHowett/go-plist"
"github.com/bitrise-io/go-utils/fileutil"
"github.com/bitrise-io/go-utils/pathutil"
+ "howett.net/plist"
)
// ExportOptions ...
diff --git a/vendor/github.com/bitrise-tools/go-xcode/exportoptions/non_appstore_options.go b/vendor/github.com/bitrise-tools/go-xcode/exportoptions/non_appstore_options.go
index 9ab04092..7eecdb20 100644
--- a/vendor/github.com/bitrise-tools/go-xcode/exportoptions/non_appstore_options.go
+++ b/vendor/github.com/bitrise-tools/go-xcode/exportoptions/non_appstore_options.go
@@ -3,7 +3,7 @@ package exportoptions
import (
"fmt"
- plist "github.com/DHowett/go-plist"
+ "howett.net/plist"
)
// NonAppStoreOptionsModel ...
diff --git a/vendor/github.com/bitrise-tools/go-xcode/models/models.go b/vendor/github.com/bitrise-tools/go-xcode/models/models.go
new file mode 100644
index 00000000..42ea3721
--- /dev/null
+++ b/vendor/github.com/bitrise-tools/go-xcode/models/models.go
@@ -0,0 +1,8 @@
+package models
+
+// XcodebuildVersionModel ...
+type XcodebuildVersionModel struct {
+ Version string
+ BuildVersion string
+ MajorVersion int64
+}
diff --git a/vendor/github.com/bitrise-tools/go-xcode/plistutil/plistutil.go b/vendor/github.com/bitrise-tools/go-xcode/plistutil/plistutil.go
new file mode 100644
index 00000000..0ca054b3
--- /dev/null
+++ b/vendor/github.com/bitrise-tools/go-xcode/plistutil/plistutil.go
@@ -0,0 +1,156 @@
+package plistutil
+
+import (
+ "time"
+
+ "github.com/bitrise-io/go-utils/fileutil"
+ "howett.net/plist"
+)
+
+// PlistData ...
+type PlistData map[string]interface{}
+
+// NewPlistDataFromContent ...
+func NewPlistDataFromContent(plistContent string) (PlistData, error) {
+ var data PlistData
+ if _, err := plist.Unmarshal([]byte(plistContent), &data); err != nil {
+ return PlistData{}, err
+ }
+ return data, nil
+}
+
+// NewPlistDataFromFile ...
+func NewPlistDataFromFile(plistPth string) (PlistData, error) {
+ content, err := fileutil.ReadStringFromFile(plistPth)
+ if err != nil {
+ return PlistData{}, err
+ }
+ return NewPlistDataFromContent(content)
+}
+
+// GetString ...
+func (data PlistData) GetString(forKey string) (string, bool) {
+ value, ok := data[forKey]
+ if !ok {
+ return "", false
+ }
+
+ casted, ok := value.(string)
+ if !ok {
+ return "", false
+ }
+
+ return casted, true
+}
+
+// GetUInt64 ...
+func (data PlistData) GetUInt64(forKey string) (uint64, bool) {
+ value, ok := data[forKey]
+ if !ok {
+ return 0, false
+ }
+
+ casted, ok := value.(uint64)
+ if !ok {
+ return 0, false
+ }
+ return casted, true
+}
+
+// GetBool ...
+func (data PlistData) GetBool(forKey string) (bool, bool) {
+ value, ok := data[forKey]
+ if !ok {
+ return false, false
+ }
+
+ casted, ok := value.(bool)
+ if !ok {
+ return false, false
+ }
+
+ return casted, true
+}
+
+// GetTime ...
+func (data PlistData) GetTime(forKey string) (time.Time, bool) {
+ value, ok := data[forKey]
+ if !ok {
+ return time.Time{}, false
+ }
+
+ casted, ok := value.(time.Time)
+ if !ok {
+ return time.Time{}, false
+ }
+ return casted, true
+}
+
+// GetUInt64Array ...
+func (data PlistData) GetUInt64Array(forKey string) ([]uint64, bool) {
+ value, ok := data[forKey]
+ if !ok {
+ return nil, false
+ }
+
+ if casted, ok := value.([]uint64); ok {
+ return casted, true
+ }
+
+ casted, ok := value.([]interface{})
+ if !ok {
+ return nil, false
+ }
+
+ array := []uint64{}
+ for _, v := range casted {
+ casted, ok := v.(uint64)
+ if !ok {
+ return nil, false
+ }
+
+ array = append(array, casted)
+ }
+ return array, true
+}
+
+// GetStringArray ...
+func (data PlistData) GetStringArray(forKey string) ([]string, bool) {
+ value, ok := data[forKey]
+ if !ok {
+ return nil, false
+ }
+
+ if casted, ok := value.([]string); ok {
+ return casted, true
+ }
+
+ casted, ok := value.([]interface{})
+ if !ok {
+ return nil, false
+ }
+
+ array := []string{}
+ for _, v := range casted {
+ casted, ok := v.(string)
+ if !ok {
+ return nil, false
+ }
+
+ array = append(array, casted)
+ }
+ return array, true
+}
+
+// GetMapStringInterface ...
+func (data PlistData) GetMapStringInterface(forKey string) (PlistData, bool) {
+ value, ok := data[forKey]
+ if !ok {
+ return nil, false
+ }
+
+ if casted, ok := value.(map[string]interface{}); ok {
+ return casted, true
+ }
+ return nil, false
+}
diff --git a/vendor/github.com/bitrise-tools/go-xcode/plistutil/plistutil_test_file_content.go b/vendor/github.com/bitrise-tools/go-xcode/plistutil/plistutil_test_file_content.go
new file mode 100644
index 00000000..2b0c2362
--- /dev/null
+++ b/vendor/github.com/bitrise-tools/go-xcode/plistutil/plistutil_test_file_content.go
@@ -0,0 +1,295 @@
+package plistutil
+
+const infoPlistContent = `
+
+
+
+ CFBundleName
+ ios-simple-objc
+ DTXcode
+ 0832
+ DTSDKName
+ iphoneos10.3
+ UILaunchStoryboardName
+ LaunchScreen
+ DTSDKBuild
+ 14E269
+ CFBundleDevelopmentRegion
+ en
+ CFBundleVersion
+ 1
+ BuildMachineOSBuild
+ 16F73
+ DTPlatformName
+ iphoneos
+ CFBundlePackageType
+ APPL
+ UIMainStoryboardFile
+ Main
+ CFBundleSupportedPlatforms
+
+ iPhoneOS
+
+ CFBundleShortVersionString
+ 1.0
+ CFBundleInfoDictionaryVersion
+ 6.0
+ UIRequiredDeviceCapabilities
+
+ armv7
+
+ CFBundleExecutable
+ ios-simple-objc
+ DTCompiler
+ com.apple.compilers.llvm.clang.1_0
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ CFBundleIdentifier
+ Bitrise.ios-simple-objc
+ MinimumOSVersion
+ 8.1
+ DTXcodeBuild
+ 8E2002
+ DTPlatformVersion
+ 10.3
+ LSRequiresIPhoneOS
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ CFBundleSignature
+ ????
+ UIDeviceFamily
+
+ 1
+ 2
+
+ DTPlatformBuild
+ 14E269
+
+
+`
+
+const developmentProfileContent = `
+
+
+
+ AppIDName
+ Bitrise Test
+ ApplicationIdentifierPrefix
+
+ 9NS4
+
+ CreationDate
+ 2016-09-22T11:28:46Z
+ Platform
+
+ iOS
+
+ DeveloperCertificates
+
+
+
+ Entitlements
+
+ keychain-access-groups
+
+ 9NS4.*
+
+ get-task-allow
+
+ application-identifier
+ 9NS4.*
+ com.apple.developer.team-identifier
+ 9NS4
+
+ ExpirationDate
+ 2017-09-22T11:28:46Z
+ Name
+ Bitrise Test Development
+ ProvisionedDevices
+
+ b138
+
+ TeamIdentifier
+
+ 9NS4
+
+ TeamName
+ Some Dude
+ TimeToLive
+ 365
+ UUID
+ 4b617a5f
+ Version
+ 1
+`
+
+const appStoreProfileContent = `
+
+
+
+ AppIDName
+ Bitrise Test
+ ApplicationIdentifierPrefix
+
+ 9NS4
+
+ CreationDate
+ 2016-09-22T11:29:12Z
+ Platform
+
+ iOS
+
+ DeveloperCertificates
+
+
+
+ Entitlements
+
+ keychain-access-groups
+
+ 9NS4.*
+
+ get-task-allow
+
+ application-identifier
+ 9NS4.*
+ com.apple.developer.team-identifier
+ 9NS4
+ beta-reports-active
+
+
+ ExpirationDate
+ 2017-09-21T13:20:06Z
+ Name
+ Bitrise Test App Store
+ TeamIdentifier
+
+ 9NS4
+
+ TeamName
+ Some Dude
+ TimeToLive
+ 364
+ UUID
+ a60668dd
+ Version
+ 1
+`
+
+const adHocProfileContent = `
+
+
+
+ AppIDName
+ Bitrise Test
+ ApplicationIdentifierPrefix
+
+ 9NS4
+
+ CreationDate
+ 2016-09-22T11:29:38Z
+ Platform
+
+ iOS
+
+ DeveloperCertificates
+
+
+
+ Entitlements
+
+ keychain-access-groups
+
+ 9NS4.*
+
+ get-task-allow
+
+ application-identifier
+ 9NS4.*
+ com.apple.developer.team-identifier
+ 9NS4
+
+ ExpirationDate
+ 2017-09-21T13:20:06Z
+ Name
+ Bitrise Test Ad Hoc
+ ProvisionedDevices
+
+ b138
+
+ TeamIdentifier
+
+ 9NS4
+
+ TeamName
+ Some Dude
+ TimeToLive
+ 364
+ UUID
+ 26668300
+ Version
+ 1
+`
+
+const enterpriseProfileContent = `
+
+
+
+ AppIDName
+ Bitrise Test
+ ApplicationIdentifierPrefix
+
+ PF3BP78LQ8
+
+ CreationDate
+ 2015-10-05T13:32:46Z
+ Platform
+
+ iOS
+
+ DeveloperCertificates
+
+
+
+ Entitlements
+
+ keychain-access-groups
+
+ PF3BP78LQ8.*
+
+ get-task-allow
+
+ application-identifier
+ 9NS4.*
+ com.apple.developer.team-identifier
+ 9NS4
+
+ ExpirationDate
+ 2016-10-04T13:32:46Z
+ Name
+ Bitrise Test Enterprise
+ ProvisionsAllDevices
+
+ TeamIdentifier
+
+ PF3BP78LQ8
+
+ TeamName
+ Some Dude
+ TimeToLive
+ 365
+ UUID
+ 8d6caa15
+ Version
+ 1
+`
diff --git a/vendor/github.com/bitrise-tools/go-xcode/provisioningprofile/provisioningprofile.go b/vendor/github.com/bitrise-tools/go-xcode/provisioningprofile/provisioningprofile.go
index 58b8afce..fb191a51 100644
--- a/vendor/github.com/bitrise-tools/go-xcode/provisioningprofile/provisioningprofile.go
+++ b/vendor/github.com/bitrise-tools/go-xcode/provisioningprofile/provisioningprofile.go
@@ -4,47 +4,25 @@ import (
"fmt"
"strings"
- plist "github.com/DHowett/go-plist"
"github.com/bitrise-io/go-utils/command"
"github.com/bitrise-tools/go-xcode/exportoptions"
+ "github.com/bitrise-tools/go-xcode/plistutil"
)
const (
notValidParameterErrorMessage = "security: SecPolicySetValue: One or more parameters passed to a function were not valid."
)
-// EntitlementsModel ...
-type EntitlementsModel struct {
- GetTaskAllow *bool `plist:"get-task-allow"`
- DeveloperTeamID *string `plist:"com.apple.developer.team-identifier"`
-}
-
-// Model ...
-type Model struct {
- Name *string `plist:"Name"`
- ProvisionedDevices *[]string `plist:"ProvisionedDevices"`
- ProvisionsAllDevices *bool `plist:"ProvisionsAllDevices"`
- Entitlements *EntitlementsModel `plist:"Entitlements"`
-}
-
-func newFromProfileContent(content string) (Model, error) {
- var mobileProvision Model
- if _, err := plist.Unmarshal([]byte(content), &mobileProvision); err != nil {
- return Model{}, fmt.Errorf("failed to mobileprovision, error: %s", err)
- }
-
- return mobileProvision, nil
-}
-
-// NewFromFile ...
-func NewFromFile(pth string) (Model, error) {
- cmd := command.New("security", "cms", "-D", "-i", pth)
+// NewPlistDataFromFile ...
+func NewPlistDataFromFile(provisioningProfilePth string) (plistutil.PlistData, error) {
+ cmd := command.New("security", "cms", "-D", "-i", provisioningProfilePth)
out, err := cmd.RunAndReturnTrimmedCombinedOutput()
if err != nil {
- return Model{}, fmt.Errorf("command failed, error: %s", err)
+ return nil, fmt.Errorf("command failed, error: %s", err)
}
+ // fix: security: SecPolicySetValue: One or more parameters passed to a function were not valid.
outSplit := strings.Split(out, "\n")
if len(outSplit) > 0 {
if strings.Contains(outSplit[0], notValidParameterErrorMessage) {
@@ -52,38 +30,42 @@ func NewFromFile(pth string) (Model, error) {
out = strings.Join(fixedOutSplit, "\n")
}
}
+ // ---
- return newFromProfileContent(out)
+ return plistutil.NewPlistDataFromContent(out)
}
// GetExportMethod ...
-func (profile Model) GetExportMethod() exportoptions.Method {
- method := exportoptions.MethodDefault
- if profile.ProvisionedDevices == nil {
- if profile.ProvisionsAllDevices != nil && *profile.ProvisionsAllDevices {
- method = exportoptions.MethodEnterprise
- } else {
- method = exportoptions.MethodAppStore
+func GetExportMethod(data plistutil.PlistData) exportoptions.Method {
+ _, ok := data.GetStringArray("ProvisionedDevices")
+ if !ok {
+ if allDevices, ok := data.GetBool("ProvisionsAllDevices"); ok && allDevices {
+ return exportoptions.MethodEnterprise
}
- } else if profile.Entitlements != nil {
- entitlements := *profile.Entitlements
- if entitlements.GetTaskAllow != nil && *entitlements.GetTaskAllow {
- method = exportoptions.MethodDevelopment
- } else {
- method = exportoptions.MethodAdHoc
+ return exportoptions.MethodAppStore
+ }
+
+ entitlements, ok := data.GetMapStringInterface("Entitlements")
+ if ok {
+ if allow, ok := entitlements.GetBool("get-task-allow"); ok && allow {
+ return exportoptions.MethodDevelopment
}
+ return exportoptions.MethodAdHoc
}
- return method
+
+ return exportoptions.MethodDefault
}
// GetDeveloperTeam ...
-func (profile Model) GetDeveloperTeam() string {
- developerTeamID := ""
- if profile.Entitlements != nil {
- entitlements := *profile.Entitlements
- if entitlements.DeveloperTeamID != nil {
- developerTeamID = *entitlements.DeveloperTeamID
- }
+func GetDeveloperTeam(data plistutil.PlistData) string {
+ entitlements, ok := data.GetMapStringInterface("Entitlements")
+ if !ok {
+ return ""
+ }
+
+ teamID, ok := entitlements.GetString("com.apple.developer.team-identifier")
+ if !ok {
+ return ""
}
- return developerTeamID
+ return teamID
}
diff --git a/vendor/github.com/bitrise-tools/go-xcode/utility/path.go b/vendor/github.com/bitrise-tools/go-xcode/utility/path.go
new file mode 100644
index 00000000..4642d3e5
--- /dev/null
+++ b/vendor/github.com/bitrise-tools/go-xcode/utility/path.go
@@ -0,0 +1,69 @@
+package utility
+
+import (
+ "io/ioutil"
+ "path/filepath"
+ "strings"
+)
+
+// FilterFunc ...
+type FilterFunc func(pth string) (bool, error)
+
+// FilterPaths ...
+func FilterPaths(paths []string, filters ...FilterFunc) ([]string, error) {
+ filtered := []string{}
+
+ for _, pth := range paths {
+ allowed := true
+ for _, filter := range filters {
+ if allows, err := filter(pth); err != nil {
+ return []string{}, err
+ } else if !allows {
+ allowed = false
+ break
+ }
+ }
+ if allowed {
+ filtered = append(filtered, pth)
+ }
+ }
+
+ return filtered, nil
+}
+
+// ListEntries ...
+func ListEntries(dir string, filters ...FilterFunc) ([]string, error) {
+ absDir, err := filepath.Abs(dir)
+ if err != nil {
+ return []string{}, err
+ }
+
+ entries, err := ioutil.ReadDir(absDir)
+ if err != nil {
+ return []string{}, err
+ }
+
+ paths := []string{}
+ for _, entry := range entries {
+ pth := filepath.Join(absDir, entry.Name())
+ paths = append(paths, pth)
+ }
+
+ return FilterPaths(paths, filters...)
+}
+
+// ExtensionFilter ...
+func ExtensionFilter(ext string, allowed bool) FilterFunc {
+ return func(pth string) (bool, error) {
+ e := filepath.Ext(pth)
+ return (allowed == strings.EqualFold(ext, e)), nil
+ }
+}
+
+// BaseFilter ...
+func BaseFilter(base string, allowed bool) FilterFunc {
+ return func(pth string) (bool, error) {
+ b := filepath.Base(pth)
+ return (allowed == strings.EqualFold(base, b)), nil
+ }
+}
diff --git a/vendor/github.com/bitrise-tools/go-xcode/utility/utility.go b/vendor/github.com/bitrise-tools/go-xcode/utility/utility.go
new file mode 100644
index 00000000..c9f94c6e
--- /dev/null
+++ b/vendor/github.com/bitrise-tools/go-xcode/utility/utility.go
@@ -0,0 +1,51 @@
+package utility
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+
+ "github.com/bitrise-io/go-utils/command"
+ "github.com/bitrise-tools/go-xcode/models"
+)
+
+func getXcodeVersionFromXcodebuildOutput(outStr string) (models.XcodebuildVersionModel, error) {
+ split := strings.Split(outStr, "\n")
+ if len(split) == 0 {
+ return models.XcodebuildVersionModel{}, fmt.Errorf("failed to parse xcodebuild version output (%s)", outStr)
+ }
+
+ xcodebuildVersion := split[0]
+ buildVersion := split[1]
+
+ split = strings.Split(xcodebuildVersion, " ")
+ if len(split) != 2 {
+ return models.XcodebuildVersionModel{}, fmt.Errorf("failed to parse xcodebuild version output (%s)", outStr)
+ }
+
+ version := split[1]
+
+ split = strings.Split(version, ".")
+ majorVersionStr := split[0]
+
+ majorVersion, err := strconv.ParseInt(majorVersionStr, 10, 32)
+ if err != nil {
+ return models.XcodebuildVersionModel{}, fmt.Errorf("failed to parse xcodebuild version output (%s), error: %s", outStr, err)
+ }
+
+ return models.XcodebuildVersionModel{
+ Version: xcodebuildVersion,
+ BuildVersion: buildVersion,
+ MajorVersion: majorVersion,
+ }, nil
+}
+
+// GetXcodeVersion ...
+func GetXcodeVersion() (models.XcodebuildVersionModel, error) {
+ cmd := command.New("xcodebuild", "-version")
+ outStr, err := cmd.RunAndReturnTrimmedCombinedOutput()
+ if err != nil {
+ return models.XcodebuildVersionModel{}, fmt.Errorf("xcodebuild -version failed, err: %s, details: %s", err, outStr)
+ }
+ return getXcodeVersionFromXcodebuildOutput(outStr)
+}
diff --git a/vendor/github.com/bitrise-tools/go-xcode/xcarchive/xcarchive.go b/vendor/github.com/bitrise-tools/go-xcode/xcarchive/xcarchive.go
index dd5471c0..d9da0b5e 100644
--- a/vendor/github.com/bitrise-tools/go-xcode/xcarchive/xcarchive.go
+++ b/vendor/github.com/bitrise-tools/go-xcode/xcarchive/xcarchive.go
@@ -4,29 +4,52 @@ import (
"fmt"
"path/filepath"
"strings"
+
+ "github.com/bitrise-io/go-utils/pathutil"
+ "github.com/bitrise-tools/go-xcode/utility"
)
-// EmbeddedMobileProvisionPth ...
-func EmbeddedMobileProvisionPth(archivePth string) (string, error) {
- applicationPth := filepath.Join(archivePth, "/Products/Applications")
- mobileProvisionPthPattern := filepath.Join(applicationPth, "*.app/embedded.mobileprovision")
- mobileProvisionPths, err := filepath.Glob(mobileProvisionPthPattern)
+// FindEmbeddedMobileProvision ...
+func FindEmbeddedMobileProvision(archivePth string) (string, error) {
+ if exist, err := pathutil.IsDirExists(archivePth); err != nil {
+ return "", fmt.Errorf("failed to check if archive exist, error: %s", err)
+ } else if !exist {
+ return "", fmt.Errorf("archive not exist at: %s", archivePth)
+ }
+
+ applicationsDirPth := filepath.Join(archivePth, "Products/Applications")
+ apps, err := utility.ListEntries(applicationsDirPth, utility.ExtensionFilter(".app", true))
if err != nil {
- return "", fmt.Errorf("failed to find embedded.mobileprovision with pattern: %s, error: %s", mobileProvisionPthPattern, err)
+ return "", err
}
- if len(mobileProvisionPths) == 0 {
- return "", fmt.Errorf("no embedded.mobileprovision with pattern: %s", mobileProvisionPthPattern)
+
+ for _, app := range apps {
+ embeddedProfiles, err := utility.ListEntries(app, utility.BaseFilter("embedded.mobileprovision", true))
+ if err != nil {
+ return "", err
+ }
+ if len(embeddedProfiles) > 0 {
+ return embeddedProfiles[0], nil
+ }
}
- return mobileProvisionPths[0], nil
+
+ return "", fmt.Errorf("no embedded.mobileprovision found")
}
// FindDSYMs ...
func FindDSYMs(archivePth string) (string, []string, error) {
- pattern := filepath.Join(archivePth, "dSYMs", "*.dSYM")
- dsyms, err := filepath.Glob(pattern)
+ if exist, err := pathutil.IsDirExists(archivePth); err != nil {
+ return "", []string{}, fmt.Errorf("failed to check if archive exist, error: %s", err)
+ } else if !exist {
+ return "", []string{}, fmt.Errorf("archive not exist at: %s", archivePth)
+ }
+
+ dsymsDirPth := filepath.Join(archivePth, "dSYMs")
+ dsyms, err := utility.ListEntries(dsymsDirPth, utility.ExtensionFilter(".dsym", true))
if err != nil {
- return "", []string{}, fmt.Errorf("failed to find dSYM with pattern: %s, error: %s", pattern, err)
+ return "", []string{}, err
}
+
appDSYM := ""
frameworkDSYMs := []string{}
for _, dsym := range dsyms {
@@ -36,19 +59,29 @@ func FindDSYMs(archivePth string) (string, []string, error) {
frameworkDSYMs = append(frameworkDSYMs, dsym)
}
}
+ if appDSYM == "" && len(frameworkDSYMs) == 0 {
+ return "", []string{}, fmt.Errorf("no dsym found")
+ }
+
return appDSYM, frameworkDSYMs, nil
}
// FindApp ...
func FindApp(archivePth string) (string, error) {
- pattern := filepath.Join(archivePth, "Products/Applications", "*.app")
- apps, err := filepath.Glob(pattern)
+ if exist, err := pathutil.IsDirExists(archivePth); err != nil {
+ return "", fmt.Errorf("failed to check if archive exist, error: %s", err)
+ } else if !exist {
+ return "", fmt.Errorf("archive not exist at: %s", archivePth)
+ }
+
+ applicationsDirPth := filepath.Join(archivePth, "Products/Applications")
+ apps, err := utility.ListEntries(applicationsDirPth, utility.ExtensionFilter(".app", true))
if err != nil {
- return "", fmt.Errorf("failed to find .app directory with pattern: %s, error: %s", pattern, err)
+ return "", err
}
if len(apps) == 0 {
- return "", fmt.Errorf("no app found with pattern (%s)", pattern)
+ return "", fmt.Errorf("no app found")
}
return apps[0], nil
diff --git a/vendor/github.com/bitrise-tools/go-xcode/xcodebuild/show_build_settings.go b/vendor/github.com/bitrise-tools/go-xcode/xcodebuild/show_build_settings.go
new file mode 100644
index 00000000..912c8575
--- /dev/null
+++ b/vendor/github.com/bitrise-tools/go-xcode/xcodebuild/show_build_settings.go
@@ -0,0 +1,88 @@
+package xcodebuild
+
+import (
+ "bufio"
+ "os/exec"
+ "strings"
+
+ "github.com/bitrise-io/go-utils/command"
+)
+
+// ShowBuildSettingsCommandModel ...
+type ShowBuildSettingsCommandModel struct {
+ projectPath string
+ isWorkspace bool
+}
+
+// NewShowBuildSettingsCommand ...
+func NewShowBuildSettingsCommand(projectPath string, isWorkspace bool) *ShowBuildSettingsCommandModel {
+ return &ShowBuildSettingsCommandModel{
+ projectPath: projectPath,
+ isWorkspace: isWorkspace,
+ }
+}
+
+func (c *ShowBuildSettingsCommandModel) cmdSlice() []string {
+ slice := []string{toolName}
+
+ if c.projectPath != "" {
+ if c.isWorkspace {
+ slice = append(slice, "-workspace", c.projectPath)
+ } else {
+ slice = append(slice, "-project", c.projectPath)
+ }
+ }
+
+ return slice
+}
+
+// PrintableCmd ...
+func (c ShowBuildSettingsCommandModel) PrintableCmd() string {
+ cmdSlice := c.cmdSlice()
+ return command.PrintableCommandArgs(false, cmdSlice)
+}
+
+// Command ...
+func (c ShowBuildSettingsCommandModel) Command() *command.Model {
+ cmdSlice := c.cmdSlice()
+ return command.New(cmdSlice[0], cmdSlice[1:]...)
+}
+
+// Cmd ...
+func (c ShowBuildSettingsCommandModel) Cmd() *exec.Cmd {
+ command := c.Command()
+ return command.GetCmd()
+}
+
+func parseBuildSettings(out string) (map[string]string, error) {
+ settings := map[string]string{}
+
+ scanner := bufio.NewScanner(strings.NewReader(out))
+ for scanner.Scan() {
+ line := strings.TrimSpace(scanner.Text())
+
+ if split := strings.Split(line, "="); len(split) == 2 {
+ key := strings.TrimSpace(split[0])
+ value := strings.TrimSpace(split[1])
+ value = strings.Trim(value, `"`)
+
+ settings[key] = value
+ }
+ }
+ if err := scanner.Err(); err != nil {
+ return map[string]string{}, err
+ }
+
+ return settings, nil
+}
+
+// RunAndReturnSettings ...
+func (c ShowBuildSettingsCommandModel) RunAndReturnSettings() (map[string]string, error) {
+ command := c.Command()
+ out, err := command.RunAndReturnTrimmedCombinedOutput()
+ if err != nil {
+ return map[string]string{}, err
+ }
+
+ return parseBuildSettings(out)
+}
diff --git a/vendor/github.com/bitrise-tools/go-xcode/xcodebuild/test.go b/vendor/github.com/bitrise-tools/go-xcode/xcodebuild/test.go
index 7dbfe1bb..2953ca38 100644
--- a/vendor/github.com/bitrise-tools/go-xcode/xcodebuild/test.go
+++ b/vendor/github.com/bitrise-tools/go-xcode/xcodebuild/test.go
@@ -1,5 +1,12 @@
package xcodebuild
+import (
+ "os"
+ "os/exec"
+
+ "github.com/bitrise-io/go-utils/command"
+)
+
/*
xcodebuild [-project ] \
-scheme \
@@ -98,8 +105,38 @@ func (c *TestCommandModel) cmdSlice() []string {
slice = append(slice, c.customBuildActions...)
slice = append(slice, "test")
-
+ if c.destination != "" {
+ slice = append(slice, "-destination", c.destination)
+ }
slice = append(slice, c.customOptions...)
return slice
}
+
+// PrintableCmd ...
+func (c TestCommandModel) PrintableCmd() string {
+ cmdSlice := c.cmdSlice()
+ return command.PrintableCommandArgs(false, cmdSlice)
+}
+
+// Command ...
+func (c TestCommandModel) Command() *command.Model {
+ cmdSlice := c.cmdSlice()
+ return command.New(cmdSlice[0], cmdSlice[1:]...)
+}
+
+// Cmd ...
+func (c TestCommandModel) Cmd() *exec.Cmd {
+ command := c.Command()
+ return command.GetCmd()
+}
+
+// Run ...
+func (c TestCommandModel) Run() error {
+ command := c.Command()
+
+ command.SetStdout(os.Stdout)
+ command.SetStderr(os.Stderr)
+
+ return command.Run()
+}
diff --git a/vendor/howett.net/plist/.travis.yml b/vendor/howett.net/plist/.travis.yml
new file mode 100644
index 00000000..b1f27e39
--- /dev/null
+++ b/vendor/howett.net/plist/.travis.yml
@@ -0,0 +1,8 @@
+language: go
+go_import_path: "howett.net/plist"
+go:
+ - 1.2
+ - master
+script:
+ - go test -v
+ - go test -tags appengine
diff --git a/vendor/github.com/DHowett/go-plist/LICENSE b/vendor/howett.net/plist/LICENSE
similarity index 100%
rename from vendor/github.com/DHowett/go-plist/LICENSE
rename to vendor/howett.net/plist/LICENSE
diff --git a/vendor/github.com/DHowett/go-plist/README.md b/vendor/howett.net/plist/README.md
similarity index 100%
rename from vendor/github.com/DHowett/go-plist/README.md
rename to vendor/howett.net/plist/README.md
diff --git a/vendor/howett.net/plist/bplist.go b/vendor/howett.net/plist/bplist.go
new file mode 100644
index 00000000..962793a9
--- /dev/null
+++ b/vendor/howett.net/plist/bplist.go
@@ -0,0 +1,26 @@
+package plist
+
+type bplistTrailer struct {
+ Unused [5]uint8
+ SortVersion uint8
+ OffsetIntSize uint8
+ ObjectRefSize uint8
+ NumObjects uint64
+ TopObject uint64
+ OffsetTableOffset uint64
+}
+
+const (
+ bpTagNull uint8 = 0x00
+ bpTagBoolFalse = 0x08
+ bpTagBoolTrue = 0x09
+ bpTagInteger = 0x10
+ bpTagReal = 0x20
+ bpTagDate = 0x30
+ bpTagData = 0x40
+ bpTagASCIIString = 0x50
+ bpTagUTF16String = 0x60
+ bpTagUID = 0x80
+ bpTagArray = 0xA0
+ bpTagDictionary = 0xD0
+)
diff --git a/vendor/howett.net/plist/bplist_generator.go b/vendor/howett.net/plist/bplist_generator.go
new file mode 100644
index 00000000..5b6513d1
--- /dev/null
+++ b/vendor/howett.net/plist/bplist_generator.go
@@ -0,0 +1,290 @@
+package plist
+
+import (
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+ "time"
+ "unicode/utf16"
+)
+
+func bplistMinimumIntSize(n uint64) int {
+ switch {
+ case n <= uint64(0xff):
+ return 1
+ case n <= uint64(0xffff):
+ return 2
+ case n <= uint64(0xffffffff):
+ return 4
+ default:
+ return 8
+ }
+}
+
+func bplistValueShouldUnique(pval cfValue) bool {
+ switch pval.(type) {
+ case cfString, *cfNumber, *cfReal, cfDate, cfData:
+ return true
+ }
+ return false
+}
+
+type bplistGenerator struct {
+ writer *countedWriter
+ objmap map[interface{}]uint64 // maps pValue.hash()es to object locations
+ objtable []cfValue
+ trailer bplistTrailer
+}
+
+func (p *bplistGenerator) flattenPlistValue(pval cfValue) {
+ key := pval.hash()
+ if bplistValueShouldUnique(pval) {
+ if _, ok := p.objmap[key]; ok {
+ return
+ }
+ }
+
+ p.objmap[key] = uint64(len(p.objtable))
+ p.objtable = append(p.objtable, pval)
+
+ switch pval := pval.(type) {
+ case *cfDictionary:
+ pval.sort()
+ for _, k := range pval.keys {
+ p.flattenPlistValue(cfString(k))
+ }
+ for _, v := range pval.values {
+ p.flattenPlistValue(v)
+ }
+ case *cfArray:
+ for _, v := range pval.values {
+ p.flattenPlistValue(v)
+ }
+ }
+}
+
+func (p *bplistGenerator) indexForPlistValue(pval cfValue) (uint64, bool) {
+ v, ok := p.objmap[pval.hash()]
+ return v, ok
+}
+
+func (p *bplistGenerator) generateDocument(root cfValue) {
+ p.objtable = make([]cfValue, 0, 16)
+ p.objmap = make(map[interface{}]uint64)
+ p.flattenPlistValue(root)
+
+ p.trailer.NumObjects = uint64(len(p.objtable))
+ p.trailer.ObjectRefSize = uint8(bplistMinimumIntSize(p.trailer.NumObjects))
+
+ p.writer.Write([]byte("bplist00"))
+
+ offtable := make([]uint64, p.trailer.NumObjects)
+ for i, pval := range p.objtable {
+ offtable[i] = uint64(p.writer.BytesWritten())
+ p.writePlistValue(pval)
+ }
+
+ p.trailer.OffsetIntSize = uint8(bplistMinimumIntSize(uint64(p.writer.BytesWritten())))
+ p.trailer.TopObject = p.objmap[root.hash()]
+ p.trailer.OffsetTableOffset = uint64(p.writer.BytesWritten())
+
+ for _, offset := range offtable {
+ p.writeSizedInt(offset, int(p.trailer.OffsetIntSize))
+ }
+
+ binary.Write(p.writer, binary.BigEndian, p.trailer)
+}
+
+func (p *bplistGenerator) writePlistValue(pval cfValue) {
+ if pval == nil {
+ return
+ }
+
+ switch pval := pval.(type) {
+ case *cfDictionary:
+ p.writeDictionaryTag(pval)
+ case *cfArray:
+ p.writeArrayTag(pval.values)
+ case cfString:
+ p.writeStringTag(string(pval))
+ case *cfNumber:
+ p.writeIntTag(pval.value)
+ case *cfReal:
+ if pval.wide {
+ p.writeRealTag(pval.value, 64)
+ } else {
+ p.writeRealTag(pval.value, 32)
+ }
+ case cfBoolean:
+ p.writeBoolTag(bool(pval))
+ case cfData:
+ p.writeDataTag([]byte(pval))
+ case cfDate:
+ p.writeDateTag(time.Time(pval))
+ case cfUID:
+ p.writeUIDTag(UID(pval))
+ default:
+ panic(fmt.Errorf("unknown plist type %t", pval))
+ }
+}
+
+func (p *bplistGenerator) writeSizedInt(n uint64, nbytes int) {
+ var val interface{}
+ switch nbytes {
+ case 1:
+ val = uint8(n)
+ case 2:
+ val = uint16(n)
+ case 4:
+ val = uint32(n)
+ case 8:
+ val = n
+ default:
+ panic(errors.New("illegal integer size"))
+ }
+ binary.Write(p.writer, binary.BigEndian, val)
+}
+
+func (p *bplistGenerator) writeBoolTag(v bool) {
+ tag := uint8(bpTagBoolFalse)
+ if v {
+ tag = bpTagBoolTrue
+ }
+ binary.Write(p.writer, binary.BigEndian, tag)
+}
+
+func (p *bplistGenerator) writeIntTag(n uint64) {
+ var tag uint8
+ var val interface{}
+ switch {
+ case n <= uint64(0xff):
+ val = uint8(n)
+ tag = bpTagInteger | 0x0
+ case n <= uint64(0xffff):
+ val = uint16(n)
+ tag = bpTagInteger | 0x1
+ case n <= uint64(0xffffffff):
+ val = uint32(n)
+ tag = bpTagInteger | 0x2
+ default:
+ val = n
+ tag = bpTagInteger | 0x3
+ }
+
+ binary.Write(p.writer, binary.BigEndian, tag)
+ binary.Write(p.writer, binary.BigEndian, val)
+}
+
+func (p *bplistGenerator) writeUIDTag(u UID) {
+ nbytes := bplistMinimumIntSize(uint64(u))
+ tag := uint8(bpTagUID | (nbytes - 1))
+
+ binary.Write(p.writer, binary.BigEndian, tag)
+ p.writeSizedInt(uint64(u), nbytes)
+}
+
+func (p *bplistGenerator) writeRealTag(n float64, bits int) {
+ var tag uint8 = bpTagReal | 0x3
+ var val interface{} = n
+ if bits == 32 {
+ val = float32(n)
+ tag = bpTagReal | 0x2
+ }
+
+ binary.Write(p.writer, binary.BigEndian, tag)
+ binary.Write(p.writer, binary.BigEndian, val)
+}
+
+func (p *bplistGenerator) writeDateTag(t time.Time) {
+ tag := uint8(bpTagDate) | 0x3
+ val := float64(t.In(time.UTC).UnixNano()) / float64(time.Second)
+ val -= 978307200 // Adjust to Apple Epoch
+
+ binary.Write(p.writer, binary.BigEndian, tag)
+ binary.Write(p.writer, binary.BigEndian, val)
+}
+
+func (p *bplistGenerator) writeCountedTag(tag uint8, count uint64) {
+ marker := tag
+ if count >= 0xF {
+ marker |= 0xF
+ } else {
+ marker |= uint8(count)
+ }
+
+ binary.Write(p.writer, binary.BigEndian, marker)
+
+ if count >= 0xF {
+ p.writeIntTag(count)
+ }
+}
+
+func (p *bplistGenerator) writeDataTag(data []byte) {
+ p.writeCountedTag(bpTagData, uint64(len(data)))
+ binary.Write(p.writer, binary.BigEndian, data)
+}
+
+func (p *bplistGenerator) writeStringTag(str string) {
+ for _, r := range str {
+ if r > 0x7F {
+ utf16Runes := utf16.Encode([]rune(str))
+ p.writeCountedTag(bpTagUTF16String, uint64(len(utf16Runes)))
+ binary.Write(p.writer, binary.BigEndian, utf16Runes)
+ return
+ }
+ }
+
+ p.writeCountedTag(bpTagASCIIString, uint64(len(str)))
+ binary.Write(p.writer, binary.BigEndian, []byte(str))
+}
+
+func (p *bplistGenerator) writeDictionaryTag(dict *cfDictionary) {
+ // assumption: sorted already; flattenPlistValue did this.
+ cnt := len(dict.keys)
+ p.writeCountedTag(bpTagDictionary, uint64(cnt))
+ vals := make([]uint64, cnt*2)
+ for i, k := range dict.keys {
+ // invariant: keys have already been "uniqued" (as PStrings)
+ keyIdx, ok := p.objmap[cfString(k).hash()]
+ if !ok {
+ panic(errors.New("failed to find key " + k + " in object map during serialization"))
+ }
+ vals[i] = keyIdx
+ }
+
+ for i, v := range dict.values {
+ // invariant: values have already been "uniqued"
+ objIdx, ok := p.indexForPlistValue(v)
+ if !ok {
+ panic(errors.New("failed to find value in object map during serialization"))
+ }
+ vals[i+cnt] = objIdx
+ }
+
+ for _, v := range vals {
+ p.writeSizedInt(v, int(p.trailer.ObjectRefSize))
+ }
+}
+
+func (p *bplistGenerator) writeArrayTag(arr []cfValue) {
+ p.writeCountedTag(bpTagArray, uint64(len(arr)))
+ for _, v := range arr {
+ objIdx, ok := p.indexForPlistValue(v)
+ if !ok {
+ panic(errors.New("failed to find value in object map during serialization"))
+ }
+
+ p.writeSizedInt(objIdx, int(p.trailer.ObjectRefSize))
+ }
+}
+
+func (p *bplistGenerator) Indent(i string) {
+ // There's nothing to indent.
+}
+
+func newBplistGenerator(w io.Writer) *bplistGenerator {
+ return &bplistGenerator{
+ writer: &countedWriter{Writer: mustWriter{w}},
+ }
+}
diff --git a/vendor/howett.net/plist/bplist_parser.go b/vendor/howett.net/plist/bplist_parser.go
new file mode 100644
index 00000000..224354bb
--- /dev/null
+++ b/vendor/howett.net/plist/bplist_parser.go
@@ -0,0 +1,338 @@
+package plist
+
+import (
+ "bytes"
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "math"
+ "runtime"
+ "time"
+ "unicode/utf16"
+)
+
+type offset uint64
+
+type bplistParser struct {
+ buffer []byte
+
+ reader io.ReadSeeker
+ version int
+ objects []cfValue // object ID to object
+ trailer bplistTrailer
+ trailerOffset uint64
+
+ containerStack []offset // slice of object offsets; manipulated during container deserialization
+}
+
+func (p *bplistParser) validateDocumentTrailer() {
+ if p.trailer.OffsetTableOffset >= p.trailerOffset {
+ panic(fmt.Errorf("offset table beyond beginning of trailer (0x%x, trailer@0x%x)", p.trailer.OffsetTableOffset, p.trailerOffset))
+ }
+
+ if p.trailer.OffsetTableOffset < 9 {
+ panic(fmt.Errorf("offset table begins inside header (0x%x)", p.trailer.OffsetTableOffset))
+ }
+
+ if p.trailerOffset > (p.trailer.NumObjects*uint64(p.trailer.OffsetIntSize))+p.trailer.OffsetTableOffset {
+ panic(errors.New("garbage between offset table and trailer"))
+ }
+
+ if p.trailer.OffsetTableOffset+(uint64(p.trailer.OffsetIntSize)*p.trailer.NumObjects) > p.trailerOffset {
+ panic(errors.New("offset table isn't long enough to address every object"))
+ }
+
+ maxObjectRef := uint64(1) << (8 * p.trailer.ObjectRefSize)
+ if p.trailer.NumObjects > maxObjectRef {
+ panic(fmt.Errorf("more objects (%v) than object ref size (%v bytes) can support", p.trailer.NumObjects, p.trailer.ObjectRefSize))
+ }
+
+ if p.trailer.OffsetIntSize < uint8(8) && (uint64(1)<<(8*p.trailer.OffsetIntSize)) <= p.trailer.OffsetTableOffset {
+ panic(errors.New("offset size isn't big enough to address entire file"))
+ }
+
+ if p.trailer.TopObject >= p.trailer.NumObjects {
+ panic(fmt.Errorf("top object #%d is out of range (only %d exist)", p.trailer.TopObject, p.trailer.NumObjects))
+ }
+}
+
+func (p *bplistParser) parseDocument() (pval cfValue, parseError error) {
+ defer func() {
+ if r := recover(); r != nil {
+ if _, ok := r.(runtime.Error); ok {
+ panic(r)
+ }
+
+ parseError = plistParseError{"binary", r.(error)}
+ }
+ }()
+
+ p.buffer, _ = ioutil.ReadAll(p.reader)
+
+ l := len(p.buffer)
+ if l < 40 {
+ panic(errors.New("not enough data"))
+ }
+
+ if !bytes.Equal(p.buffer[0:6], []byte{'b', 'p', 'l', 'i', 's', 't'}) {
+ panic(errors.New("incomprehensible magic"))
+ }
+
+ p.version = int(((p.buffer[6] - '0') * 10) + (p.buffer[7] - '0'))
+
+ if p.version > 1 {
+ panic(fmt.Errorf("unexpected version %d", p.version))
+ }
+
+ p.trailerOffset = uint64(l - 32)
+ p.trailer = bplistTrailer{
+ SortVersion: p.buffer[p.trailerOffset+5],
+ OffsetIntSize: p.buffer[p.trailerOffset+6],
+ ObjectRefSize: p.buffer[p.trailerOffset+7],
+ NumObjects: binary.BigEndian.Uint64(p.buffer[p.trailerOffset+8:]),
+ TopObject: binary.BigEndian.Uint64(p.buffer[p.trailerOffset+16:]),
+ OffsetTableOffset: binary.BigEndian.Uint64(p.buffer[p.trailerOffset+24:]),
+ }
+
+ p.validateDocumentTrailer()
+
+ // INVARIANTS:
+ // - Entire offset table is before trailer
+ // - Offset table begins after header
+ // - Offset table can address entire document
+ // - Object IDs are big enough to support the number of objects in this plist
+ // - Top object is in range
+
+ p.objects = make([]cfValue, p.trailer.NumObjects)
+
+ pval = p.objectAtIndex(p.trailer.TopObject)
+ return
+}
+
+// parseSizedInteger returns a 128-bit integer as low64, high64
+func (p *bplistParser) parseSizedInteger(off offset, nbytes int) (uint64, uint64, offset) {
+ switch nbytes {
+ case 1:
+ return uint64(p.buffer[off]), 0, off + offset(nbytes)
+ case 2:
+ return uint64(binary.BigEndian.Uint16(p.buffer[off:])), 0, off + offset(nbytes)
+ case 4:
+ return uint64(binary.BigEndian.Uint32(p.buffer[off:])), 0, off + offset(nbytes)
+ case 8:
+ return binary.BigEndian.Uint64(p.buffer[off:]), 0, off + offset(nbytes)
+ case 16:
+ return binary.BigEndian.Uint64(p.buffer[off+8:]), binary.BigEndian.Uint64(p.buffer[off:]), off + offset(nbytes)
+ }
+ panic(errors.New("illegal integer size"))
+}
+
+func (p *bplistParser) parseObjectRefAtOffset(off offset) (uint64, offset) {
+ oid, _, next := p.parseSizedInteger(off, int(p.trailer.ObjectRefSize))
+ return oid, next
+}
+
+func (p *bplistParser) parseOffsetAtOffset(off offset) (offset, offset) {
+ parsedOffset, _, next := p.parseSizedInteger(off, int(p.trailer.OffsetIntSize))
+ return offset(parsedOffset), next
+}
+
+func (p *bplistParser) objectAtIndex(index uint64) cfValue {
+ if index >= p.trailer.NumObjects {
+ panic(fmt.Errorf("invalid object#%d (max %d)", index, p.trailer.NumObjects))
+ }
+
+ if pval := p.objects[index]; pval != nil {
+ return pval
+ }
+
+ off, _ := p.parseOffsetAtOffset(offset(p.trailer.OffsetTableOffset + (index * uint64(p.trailer.OffsetIntSize))))
+ if off > offset(p.trailer.OffsetTableOffset-1) {
+ panic(fmt.Errorf("object#%d starts beyond beginning of object table (0x%x, table@0x%x)", index, off, p.trailer.OffsetTableOffset))
+ }
+
+ pval := p.parseTagAtOffset(off)
+ p.objects[index] = pval
+ return pval
+
+}
+
+func (p *bplistParser) pushNestedObject(off offset) {
+ for _, v := range p.containerStack {
+ if v == off {
+ p.panicNestedObject(off)
+ }
+ }
+ p.containerStack = append(p.containerStack, off)
+}
+
+func (p *bplistParser) panicNestedObject(off offset) {
+ ids := ""
+ for _, v := range p.containerStack {
+ ids += fmt.Sprintf("0x%x > ", v)
+ }
+
+ // %s0x%d: ids above ends with " > "
+ panic(fmt.Errorf("self-referential collection@0x%x (%s0x%x) cannot be deserialized", off, ids, off))
+}
+
+func (p *bplistParser) popNestedObject() {
+ p.containerStack = p.containerStack[:len(p.containerStack)-1]
+}
+
+func (p *bplistParser) parseTagAtOffset(off offset) cfValue {
+ tag := p.buffer[off]
+
+ switch tag & 0xF0 {
+ case bpTagNull:
+ switch tag & 0x0F {
+ case bpTagBoolTrue, bpTagBoolFalse:
+ return cfBoolean(tag == bpTagBoolTrue)
+ }
+ case bpTagInteger:
+ lo, hi, _ := p.parseIntegerAtOffset(off)
+ return &cfNumber{
+ signed: hi == 0xFFFFFFFFFFFFFFFF, // a signed integer is stored as a 128-bit integer with the top 64 bits set
+ value: lo,
+ }
+ case bpTagReal:
+ nbytes := 1 << (tag & 0x0F)
+ switch nbytes {
+ case 4:
+ bits := binary.BigEndian.Uint32(p.buffer[off+1:])
+ return &cfReal{wide: false, value: float64(math.Float32frombits(bits))}
+ case 8:
+ bits := binary.BigEndian.Uint64(p.buffer[off+1:])
+ return &cfReal{wide: true, value: math.Float64frombits(bits)}
+ }
+ panic(errors.New("illegal float size"))
+ case bpTagDate:
+ bits := binary.BigEndian.Uint64(p.buffer[off+1:])
+ val := math.Float64frombits(bits)
+
+ // Apple Epoch is 20110101000000Z
+ // Adjust for UNIX Time
+ val += 978307200
+
+ sec, fsec := math.Modf(val)
+ time := time.Unix(int64(sec), int64(fsec*float64(time.Second))).In(time.UTC)
+ return cfDate(time)
+ case bpTagData:
+ data := p.parseDataAtOffset(off)
+ return cfData(data)
+ case bpTagASCIIString:
+ str := p.parseASCIIStringAtOffset(off)
+ return cfString(str)
+ case bpTagUTF16String:
+ str := p.parseUTF16StringAtOffset(off)
+ return cfString(str)
+ case bpTagUID: // Somehow different than int: low half is nbytes - 1 instead of log2(nbytes)
+ lo, _, _ := p.parseSizedInteger(off+1, int(tag&0xF)+1)
+ return cfUID(lo)
+ case bpTagDictionary:
+ return p.parseDictionaryAtOffset(off)
+ case bpTagArray:
+ return p.parseArrayAtOffset(off)
+ }
+ panic(fmt.Errorf("unexpected atom 0x%2.02x at offset 0x%x", tag, off))
+}
+
+func (p *bplistParser) parseIntegerAtOffset(off offset) (uint64, uint64, offset) {
+ tag := p.buffer[off]
+ return p.parseSizedInteger(off+1, 1<<(tag&0xF))
+}
+
+func (p *bplistParser) countForTagAtOffset(off offset) (uint64, offset) {
+ tag := p.buffer[off]
+ cnt := uint64(tag & 0x0F)
+ if cnt == 0xF {
+ cnt, _, off = p.parseIntegerAtOffset(off + 1)
+ return cnt, off
+ }
+ return cnt, off + 1
+}
+
+func (p *bplistParser) parseDataAtOffset(off offset) []byte {
+ len, start := p.countForTagAtOffset(off)
+ if start+offset(len) > offset(p.trailer.OffsetTableOffset) {
+ panic(fmt.Errorf("data@0x%x too long (%v bytes, max is %v)", off, len, p.trailer.OffsetTableOffset-uint64(start)))
+ }
+ return p.buffer[start : start+offset(len)]
+}
+
+func (p *bplistParser) parseASCIIStringAtOffset(off offset) string {
+ len, start := p.countForTagAtOffset(off)
+ if start+offset(len) > offset(p.trailer.OffsetTableOffset) {
+ panic(fmt.Errorf("ascii string@0x%x too long (%v bytes, max is %v)", off, len, p.trailer.OffsetTableOffset-uint64(start)))
+ }
+
+ return zeroCopy8BitString(p.buffer, int(start), int(len))
+}
+
+func (p *bplistParser) parseUTF16StringAtOffset(off offset) string {
+ len, start := p.countForTagAtOffset(off)
+ bytes := len * 2
+ if start+offset(bytes) > offset(p.trailer.OffsetTableOffset) {
+ panic(fmt.Errorf("utf16 string@0x%x too long (%v bytes, max is %v)", off, bytes, p.trailer.OffsetTableOffset-uint64(start)))
+ }
+
+ u16s := make([]uint16, len)
+ for i := offset(0); i < offset(len); i++ {
+ u16s[i] = binary.BigEndian.Uint16(p.buffer[start+(i*2):])
+ }
+ runes := utf16.Decode(u16s)
+ return string(runes)
+}
+
+func (p *bplistParser) parseObjectListAtOffset(off offset, count uint64) []cfValue {
+ if off+offset(count*uint64(p.trailer.ObjectRefSize)) > offset(p.trailer.OffsetTableOffset) {
+ panic(fmt.Errorf("list@0x%x length (%v) puts its end beyond the offset table at 0x%x", off, count, p.trailer.OffsetTableOffset))
+ }
+ objects := make([]cfValue, count)
+
+ next := off
+ var oid uint64
+ for i := uint64(0); i < count; i++ {
+ oid, next = p.parseObjectRefAtOffset(next)
+ objects[i] = p.objectAtIndex(oid)
+ }
+
+ return objects
+}
+
+func (p *bplistParser) parseDictionaryAtOffset(off offset) *cfDictionary {
+ p.pushNestedObject(off)
+ defer p.popNestedObject()
+
+ // a dictionary is an object list of [key key key val val val]
+ cnt, start := p.countForTagAtOffset(off)
+ objects := p.parseObjectListAtOffset(start, cnt*2)
+
+ keys := make([]string, cnt)
+ for i := uint64(0); i < cnt; i++ {
+ if str, ok := objects[i].(cfString); ok {
+ keys[i] = string(str)
+ } else {
+ panic(fmt.Errorf("dictionary@0x%x contains non-string key at index %d", off, i))
+ }
+ }
+
+ return &cfDictionary{
+ keys: keys,
+ values: objects[cnt:],
+ }
+}
+
+func (p *bplistParser) parseArrayAtOffset(off offset) *cfArray {
+ p.pushNestedObject(off)
+ defer p.popNestedObject()
+
+ // an array is just an object list
+ cnt, start := p.countForTagAtOffset(off)
+ return &cfArray{p.parseObjectListAtOffset(start, cnt)}
+}
+
+func newBplistParser(r io.ReadSeeker) *bplistParser {
+ return &bplistParser{reader: r}
+}
diff --git a/vendor/github.com/DHowett/go-plist/decode.go b/vendor/howett.net/plist/decode.go
similarity index 96%
rename from vendor/github.com/DHowett/go-plist/decode.go
rename to vendor/howett.net/plist/decode.go
index a927d6de..4c646677 100644
--- a/vendor/github.com/DHowett/go-plist/decode.go
+++ b/vendor/howett.net/plist/decode.go
@@ -8,7 +8,7 @@ import (
)
type parser interface {
- parseDocument() (*plistValue, error)
+ parseDocument() (cfValue, error)
}
// A Decoder reads a property list from an input stream.
@@ -38,7 +38,7 @@ func (p *Decoder) Decode(v interface{}) (err error) {
p.reader.Seek(0, 0)
var parser parser
- var pval *plistValue
+ var pval cfValue
if bytes.Equal(header, []byte("bplist")) {
parser = newBplistParser(p.reader)
pval, err = parser.parseDocument()
@@ -93,6 +93,7 @@ func NewDecoder(r io.ReadSeeker) *Decoder {
// in the interface value. If the interface value is nil, Unmarshal stores one of the following in the interface value:
//
// string, bool, uint64, float64
+// plist.UID for "CoreFoundation Keyed Archiver UIDs" (convertible to uint64)
// []byte, for plist data
// []interface{}, for plist arrays
// map[string]interface{}, for plist dictionaries
diff --git a/vendor/github.com/DHowett/go-plist/doc.go b/vendor/howett.net/plist/doc.go
similarity index 100%
rename from vendor/github.com/DHowett/go-plist/doc.go
rename to vendor/howett.net/plist/doc.go
diff --git a/vendor/github.com/DHowett/go-plist/encode.go b/vendor/howett.net/plist/encode.go
similarity index 99%
rename from vendor/github.com/DHowett/go-plist/encode.go
rename to vendor/howett.net/plist/encode.go
index 743da9c1..f81309b5 100644
--- a/vendor/github.com/DHowett/go-plist/encode.go
+++ b/vendor/howett.net/plist/encode.go
@@ -9,7 +9,7 @@ import (
)
type generator interface {
- generateDocument(*plistValue)
+ generateDocument(cfValue)
Indent(string)
}
diff --git a/vendor/github.com/DHowett/go-plist/fuzz.go b/vendor/howett.net/plist/fuzz.go
similarity index 100%
rename from vendor/github.com/DHowett/go-plist/fuzz.go
rename to vendor/howett.net/plist/fuzz.go
diff --git a/vendor/github.com/DHowett/go-plist/marshal.go b/vendor/howett.net/plist/marshal.go
similarity index 54%
rename from vendor/github.com/DHowett/go-plist/marshal.go
rename to vendor/howett.net/plist/marshal.go
index 81e79b1e..c461dfb5 100644
--- a/vendor/github.com/DHowett/go-plist/marshal.go
+++ b/vendor/howett.net/plist/marshal.go
@@ -25,45 +25,76 @@ func isEmptyValue(v reflect.Value) bool {
}
var (
- textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
- timeType = reflect.TypeOf((*time.Time)(nil)).Elem()
+ plistMarshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem()
+ textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
+ timeType = reflect.TypeOf((*time.Time)(nil)).Elem()
)
-func (p *Encoder) marshalTextInterface(marshalable encoding.TextMarshaler) *plistValue {
+func implementsInterface(val reflect.Value, interfaceType reflect.Type) (interface{}, bool) {
+ if val.CanInterface() && val.Type().Implements(interfaceType) {
+ return val.Interface(), true
+ }
+
+ if val.CanAddr() {
+ pv := val.Addr()
+ if pv.CanInterface() && pv.Type().Implements(interfaceType) {
+ return pv.Interface(), true
+ }
+ }
+ return nil, false
+}
+
+func (p *Encoder) marshalPlistInterface(marshalable Marshaler) cfValue {
+ value, err := marshalable.MarshalPlist()
+ if err != nil {
+ panic(err)
+ }
+ return p.marshal(reflect.ValueOf(value))
+}
+
+// marshalTextInterface marshals a TextMarshaler to a plist string.
+func (p *Encoder) marshalTextInterface(marshalable encoding.TextMarshaler) cfValue {
s, err := marshalable.MarshalText()
if err != nil {
panic(err)
}
- return &plistValue{String, string(s)}
+ return cfString(s)
}
-func (p *Encoder) marshalStruct(typ reflect.Type, val reflect.Value) *plistValue {
+// marshalStruct marshals a reflected struct value to a plist dictionary
+func (p *Encoder) marshalStruct(typ reflect.Type, val reflect.Value) cfValue {
tinfo, _ := getTypeInfo(typ)
- dict := &dictionary{
- m: make(map[string]*plistValue, len(tinfo.fields)),
+ dict := &cfDictionary{
+ keys: make([]string, 0, len(tinfo.fields)),
+ values: make([]cfValue, 0, len(tinfo.fields)),
}
for _, finfo := range tinfo.fields {
value := finfo.value(val)
if !value.IsValid() || finfo.omitEmpty && isEmptyValue(value) {
continue
}
- dict.m[finfo.name] = p.marshal(value)
+ dict.keys = append(dict.keys, finfo.name)
+ dict.values = append(dict.values, p.marshal(value))
}
- return &plistValue{Dictionary, dict}
+ return dict
}
-func (p *Encoder) marshalTime(val reflect.Value) *plistValue {
+func (p *Encoder) marshalTime(val reflect.Value) cfValue {
time := val.Interface().(time.Time)
- return &plistValue{Date, time}
+ return cfDate(time)
}
-func (p *Encoder) marshal(val reflect.Value) *plistValue {
+func (p *Encoder) marshal(val reflect.Value) cfValue {
if !val.IsValid() {
return nil
}
+ if receiver, can := implementsInterface(val, plistMarshalerType); can {
+ return p.marshalPlistInterface(receiver.(Marshaler))
+ }
+
// time.Time implements TextMarshaler, but we need to store it in RFC3339
if val.Type() == timeType {
return p.marshalTime(val)
@@ -76,14 +107,8 @@ func (p *Encoder) marshal(val reflect.Value) *plistValue {
}
// Check for text marshaler.
- if val.CanInterface() && val.Type().Implements(textMarshalerType) {
- return p.marshalTextInterface(val.Interface().(encoding.TextMarshaler))
- }
- if val.CanAddr() {
- pv := val.Addr()
- if pv.CanInterface() && pv.Type().Implements(textMarshalerType) {
- return p.marshalTextInterface(pv.Interface().(encoding.TextMarshaler))
- }
+ if receiver, can := implementsInterface(val, textMarshalerType); can {
+ return p.marshalTextInterface(receiver.(encoding.TextMarshaler))
}
// Descend into pointers or interfaces
@@ -98,21 +123,27 @@ func (p *Encoder) marshal(val reflect.Value) *plistValue {
typ := val.Type()
+ if typ == uidType {
+ return cfUID(val.Uint())
+ }
+
if val.Kind() == reflect.Struct {
return p.marshalStruct(typ, val)
}
switch val.Kind() {
case reflect.String:
- return &plistValue{String, val.String()}
+ return cfString(val.String())
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- return &plistValue{Integer, signedInt{uint64(val.Int()), true}}
+ return &cfNumber{signed: true, value: uint64(val.Int())}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- return &plistValue{Integer, signedInt{uint64(val.Uint()), false}}
- case reflect.Float32, reflect.Float64:
- return &plistValue{Real, sizedFloat{val.Float(), val.Type().Bits()}}
+ return &cfNumber{signed: false, value: val.Uint()}
+ case reflect.Float32:
+ return &cfReal{wide: false, value: val.Float()}
+ case reflect.Float64:
+ return &cfReal{wide: true, value: val.Float()}
case reflect.Bool:
- return &plistValue{Boolean, val.Bool()}
+ return cfBoolean(val.Bool())
case reflect.Slice, reflect.Array:
if typ.Elem().Kind() == reflect.Uint8 {
bytes := []byte(nil)
@@ -122,15 +153,15 @@ func (p *Encoder) marshal(val reflect.Value) *plistValue {
bytes = make([]byte, val.Len())
reflect.Copy(reflect.ValueOf(bytes), val)
}
- return &plistValue{Data, bytes}
+ return cfData(bytes)
} else {
- subvalues := make([]*plistValue, val.Len())
- for idx, length := 0, val.Len(); idx < length; idx++ {
- if subpval := p.marshal(val.Index(idx)); subpval != nil {
- subvalues[idx] = subpval
+ values := make([]cfValue, val.Len())
+ for i, length := 0, val.Len(); i < length; i++ {
+ if subpval := p.marshal(val.Index(i)); subpval != nil {
+ values[i] = subpval
}
}
- return &plistValue{Array, subvalues}
+ return &cfArray{values}
}
case reflect.Map:
if typ.Key().Kind() != reflect.String {
@@ -138,17 +169,18 @@ func (p *Encoder) marshal(val reflect.Value) *plistValue {
}
l := val.Len()
- dict := &dictionary{
- m: make(map[string]*plistValue, l),
+ dict := &cfDictionary{
+ keys: make([]string, 0, l),
+ values: make([]cfValue, 0, l),
}
for _, keyv := range val.MapKeys() {
if subpval := p.marshal(val.MapIndex(keyv)); subpval != nil {
- dict.m[keyv.String()] = subpval
+ dict.keys = append(dict.keys, keyv.String())
+ dict.values = append(dict.values, subpval)
}
}
- return &plistValue{Dictionary, dict}
+ return dict
default:
panic(&unknownTypeError{typ})
}
- return nil
}
diff --git a/vendor/github.com/DHowett/go-plist/must.go b/vendor/howett.net/plist/must.go
similarity index 100%
rename from vendor/github.com/DHowett/go-plist/must.go
rename to vendor/howett.net/plist/must.go
diff --git a/vendor/howett.net/plist/plist.go b/vendor/howett.net/plist/plist.go
new file mode 100644
index 00000000..a4078b23
--- /dev/null
+++ b/vendor/howett.net/plist/plist.go
@@ -0,0 +1,85 @@
+package plist
+
+import (
+ "reflect"
+)
+
+// 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 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
+}
+
+// A UID represents a unique object identifier. UIDs are serialized in a manner distinct from
+// that of integers.
+//
+// UIDs cannot be serialized in OpenStepFormat or GNUStepFormat property lists.
+type UID uint64
+
+// Marshaler is the interface implemented by types that can marshal themselves into valid
+// property list objects. The returned value is marshaled in place of the original value
+// implementing Marshaler
+//
+// If an error is returned by MarshalPlist, marshaling stops and the error is returned.
+type Marshaler interface {
+ MarshalPlist() (interface{}, error)
+}
+
+// Unmarshaler is the interface implemented by types that can unmarshal themselves from
+// property list objects. The UnmarshalPlist method receives a function that may
+// be called to unmarshal the original property list value into a field or variable.
+//
+// It is safe to call the unmarshal function more than once.
+type Unmarshaler interface {
+ UnmarshalPlist(unmarshal func(interface{}) error) error
+}
diff --git a/vendor/howett.net/plist/plist_types.go b/vendor/howett.net/plist/plist_types.go
new file mode 100644
index 00000000..954ef34e
--- /dev/null
+++ b/vendor/howett.net/plist/plist_types.go
@@ -0,0 +1,139 @@
+package plist
+
+import (
+ "hash/crc32"
+ "sort"
+ "time"
+)
+
+type cfValue interface {
+ typeName() string
+ hash() interface{}
+}
+
+type cfDictionary struct {
+ keys sort.StringSlice
+ values []cfValue
+}
+
+func (*cfDictionary) typeName() string {
+ return "dictionary"
+}
+
+func (p *cfDictionary) hash() interface{} {
+ return p
+}
+
+func (p *cfDictionary) Len() int {
+ return len(p.keys)
+}
+
+func (p *cfDictionary) Less(i, j int) bool {
+ return p.keys.Less(i, j)
+}
+
+func (p *cfDictionary) Swap(i, j int) {
+ p.keys.Swap(i, j)
+ p.values[i], p.values[j] = p.values[j], p.values[i]
+}
+
+func (p *cfDictionary) sort() {
+ sort.Sort(p)
+}
+
+type cfArray struct {
+ values []cfValue
+}
+
+func (*cfArray) typeName() string {
+ return "array"
+}
+
+func (p *cfArray) hash() interface{} {
+ return p
+}
+
+type cfString string
+
+func (cfString) typeName() string {
+ return "string"
+}
+
+func (p cfString) hash() interface{} {
+ return string(p)
+}
+
+type cfNumber struct {
+ signed bool
+ value uint64
+}
+
+func (*cfNumber) typeName() string {
+ return "integer"
+}
+
+func (p *cfNumber) hash() interface{} {
+ if p.signed {
+ return int64(p.value)
+ }
+ return p.value
+}
+
+type cfReal struct {
+ wide bool
+ value float64
+}
+
+func (cfReal) typeName() string {
+ return "real"
+}
+
+func (p *cfReal) hash() interface{} {
+ if p.wide {
+ return p.value
+ }
+ return float32(p.value)
+}
+
+type cfBoolean bool
+
+func (cfBoolean) typeName() string {
+ return "boolean"
+}
+
+func (p cfBoolean) hash() interface{} {
+ return bool(p)
+}
+
+type cfUID UID
+
+func (cfUID) typeName() string {
+ return "UID"
+}
+
+func (p cfUID) hash() interface{} {
+ return p
+}
+
+type cfData []byte
+
+func (cfData) typeName() string {
+ return "data"
+}
+
+func (p cfData) hash() interface{} {
+ // Data are uniqued by their checksums.
+ // Todo: Look at calculating this only once and storing it somewhere;
+ // crc32 is fairly quick, however.
+ return crc32.ChecksumIEEE([]byte(p))
+}
+
+type cfDate time.Time
+
+func (cfDate) typeName() string {
+ return "date"
+}
+
+func (p cfDate) hash() interface{} {
+ return time.Time(p)
+}
diff --git a/vendor/howett.net/plist/text_generator.go b/vendor/howett.net/plist/text_generator.go
new file mode 100644
index 00000000..53078ba5
--- /dev/null
+++ b/vendor/howett.net/plist/text_generator.go
@@ -0,0 +1,226 @@
+package plist
+
+import (
+ "encoding/hex"
+ "io"
+ "strconv"
+ "time"
+)
+
+type textPlistGenerator struct {
+ writer io.Writer
+ format int
+
+ quotableTable *characterSet
+
+ indent string
+ depth int
+
+ dictKvDelimiter, dictEntryDelimiter, arrayDelimiter []byte
+}
+
+var (
+ textPlistTimeLayout = "2006-01-02 15:04:05 -0700"
+ padding = "0000"
+)
+
+func (p *textPlistGenerator) generateDocument(pval cfValue) {
+ p.writePlistValue(pval)
+}
+
+func (p *textPlistGenerator) plistQuotedString(str string) string {
+ if str == "" {
+ return `""`
+ }
+ s := ""
+ quot := false
+ for _, r := range str {
+ if r > 0xFF {
+ quot = true
+ s += `\U`
+ us := strconv.FormatInt(int64(r), 16)
+ s += padding[len(us):]
+ s += us
+ } else if r > 0x7F {
+ quot = true
+ s += `\`
+ us := strconv.FormatInt(int64(r), 8)
+ s += padding[1+len(us):]
+ s += us
+ } else {
+ c := uint8(r)
+ if p.quotableTable.ContainsByte(c) {
+ quot = true
+ }
+
+ switch c {
+ case '\a':
+ s += `\a`
+ case '\b':
+ s += `\b`
+ case '\v':
+ s += `\v`
+ case '\f':
+ s += `\f`
+ case '\\':
+ s += `\\`
+ case '"':
+ s += `\"`
+ case '\t', '\r', '\n':
+ fallthrough
+ default:
+ s += string(c)
+ }
+ }
+ }
+ if quot {
+ s = `"` + s + `"`
+ }
+ return s
+}
+
+func (p *textPlistGenerator) deltaIndent(depthDelta int) {
+ if depthDelta < 0 {
+ p.depth--
+ } else if depthDelta > 0 {
+ p.depth++
+ }
+}
+
+func (p *textPlistGenerator) writeIndent() {
+ if len(p.indent) == 0 {
+ return
+ }
+ if len(p.indent) > 0 {
+ p.writer.Write([]byte("\n"))
+ for i := 0; i < p.depth; i++ {
+ io.WriteString(p.writer, p.indent)
+ }
+ }
+}
+
+func (p *textPlistGenerator) writePlistValue(pval cfValue) {
+ if pval == nil {
+ return
+ }
+
+ switch pval := pval.(type) {
+ case *cfDictionary:
+ pval.sort()
+ p.writer.Write([]byte(`{`))
+ p.deltaIndent(1)
+ for i, k := range pval.keys {
+ p.writeIndent()
+ io.WriteString(p.writer, p.plistQuotedString(k))
+ p.writer.Write(p.dictKvDelimiter)
+ p.writePlistValue(pval.values[i])
+ p.writer.Write(p.dictEntryDelimiter)
+ }
+ p.deltaIndent(-1)
+ p.writeIndent()
+ p.writer.Write([]byte(`}`))
+ case *cfArray:
+ p.writer.Write([]byte(`(`))
+ p.deltaIndent(1)
+ for _, v := range pval.values {
+ p.writeIndent()
+ p.writePlistValue(v)
+ p.writer.Write(p.arrayDelimiter)
+ }
+ p.deltaIndent(-1)
+ p.writeIndent()
+ p.writer.Write([]byte(`)`))
+ case cfString:
+ io.WriteString(p.writer, p.plistQuotedString(string(pval)))
+ case *cfNumber:
+ if p.format == GNUStepFormat {
+ p.writer.Write([]byte(`<*I`))
+ }
+ if pval.signed {
+ io.WriteString(p.writer, strconv.FormatInt(int64(pval.value), 10))
+ } else {
+ io.WriteString(p.writer, strconv.FormatUint(pval.value, 10))
+ }
+ if p.format == GNUStepFormat {
+ p.writer.Write([]byte(`>`))
+ }
+ case *cfReal:
+ if p.format == GNUStepFormat {
+ p.writer.Write([]byte(`<*R`))
+ }
+ // GNUstep does not differentiate between 32/64-bit floats.
+ io.WriteString(p.writer, strconv.FormatFloat(pval.value, 'g', -1, 64))
+ if p.format == GNUStepFormat {
+ p.writer.Write([]byte(`>`))
+ }
+ case cfBoolean:
+ if p.format == GNUStepFormat {
+ if pval {
+ p.writer.Write([]byte(`<*BY>`))
+ } else {
+ p.writer.Write([]byte(`<*BN>`))
+ }
+ } else {
+ if pval {
+ p.writer.Write([]byte(`1`))
+ } else {
+ p.writer.Write([]byte(`0`))
+ }
+ }
+ case cfData:
+ var hexencoded [9]byte
+ var l int
+ var asc = 9
+ hexencoded[8] = ' '
+
+ p.writer.Write([]byte(`<`))
+ b := []byte(pval)
+ for i := 0; i < len(b); i += 4 {
+ l = i + 4
+ if l >= len(b) {
+ l = len(b)
+ // We no longer need the space - or the rest of the buffer.
+ // (we used >= above to get this part without another conditional :P)
+ asc = (l - i) * 2
+ }
+ // Fill the buffer (only up to 8 characters, to preserve the space we implicitly include
+ // at the end of every encode)
+ hex.Encode(hexencoded[:8], b[i:l])
+ io.WriteString(p.writer, string(hexencoded[:asc]))
+ }
+ p.writer.Write([]byte(`>`))
+ case cfDate:
+ if p.format == GNUStepFormat {
+ p.writer.Write([]byte(`<*D`))
+ io.WriteString(p.writer, time.Time(pval).In(time.UTC).Format(textPlistTimeLayout))
+ p.writer.Write([]byte(`>`))
+ } else {
+ io.WriteString(p.writer, p.plistQuotedString(time.Time(pval).In(time.UTC).Format(textPlistTimeLayout)))
+ }
+ }
+}
+
+func (p *textPlistGenerator) Indent(i string) {
+ p.indent = i
+ if i == "" {
+ p.dictKvDelimiter = []byte(`=`)
+ } else {
+ // For pretty-printing
+ p.dictKvDelimiter = []byte(` = `)
+ }
+}
+
+func newTextPlistGenerator(w io.Writer, format int) *textPlistGenerator {
+ table := &osQuotable
+ if format == GNUStepFormat {
+ table = &gsQuotable
+ }
+ return &textPlistGenerator{
+ writer: mustWriter{w},
+ format: format,
+ quotableTable: table,
+ dictKvDelimiter: []byte(`=`),
+ arrayDelimiter: []byte(`,`),
+ dictEntryDelimiter: []byte(`;`),
+ }
+}
diff --git a/vendor/howett.net/plist/text_parser.go b/vendor/howett.net/plist/text_parser.go
new file mode 100644
index 00000000..7e49d6f7
--- /dev/null
+++ b/vendor/howett.net/plist/text_parser.go
@@ -0,0 +1,515 @@
+package plist
+
+import (
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "runtime"
+ "strings"
+ "time"
+ "unicode/utf16"
+ "unicode/utf8"
+)
+
+type textPlistParser struct {
+ reader io.Reader
+ format int
+
+ input string
+ start int
+ pos int
+ width int
+}
+
+func convertU16(buffer []byte, bo binary.ByteOrder) (string, error) {
+ if len(buffer)%2 != 0 {
+ return "", errors.New("truncated utf16")
+ }
+
+ tmp := make([]uint16, len(buffer)/2)
+ for i := 0; i < len(buffer); i += 2 {
+ tmp[i/2] = bo.Uint16(buffer[i : i+2])
+ }
+ return string(utf16.Decode(tmp)), nil
+}
+
+func guessEncodingAndConvert(buffer []byte) (string, error) {
+ if len(buffer) >= 3 && buffer[0] == 0xEF && buffer[1] == 0xBB && buffer[2] == 0xBF {
+ // UTF-8 BOM
+ return zeroCopy8BitString(buffer, 3, len(buffer)-3), nil
+ } else if len(buffer) >= 2 {
+ // UTF-16 guesses
+
+ switch {
+ // stream is big-endian (BOM is FE FF or head is 00 XX)
+ case (buffer[0] == 0xFE && buffer[1] == 0xFF):
+ return convertU16(buffer[2:], binary.BigEndian)
+ case (buffer[0] == 0 && buffer[1] != 0):
+ return convertU16(buffer, binary.BigEndian)
+
+ // stream is little-endian (BOM is FE FF or head is XX 00)
+ case (buffer[0] == 0xFF && buffer[1] == 0xFE):
+ return convertU16(buffer[2:], binary.LittleEndian)
+ case (buffer[0] != 0 && buffer[1] == 0):
+ return convertU16(buffer, binary.LittleEndian)
+ }
+ }
+
+ // fallback: assume ASCII (not great!)
+ return zeroCopy8BitString(buffer, 0, len(buffer)), nil
+}
+
+func (p *textPlistParser) parseDocument() (pval cfValue, parseError error) {
+ defer func() {
+ if r := recover(); r != nil {
+ if _, ok := r.(runtime.Error); ok {
+ panic(r)
+ }
+ // Wrap all non-invalid-plist errors.
+ parseError = plistParseError{"text", r.(error)}
+ }
+ }()
+
+ buffer, err := ioutil.ReadAll(p.reader)
+ if err != nil {
+ panic(err)
+ }
+
+ p.input, err = guessEncodingAndConvert(buffer)
+ if err != nil {
+ panic(err)
+ }
+
+ val := p.parsePlistValue()
+
+ p.skipWhitespaceAndComments()
+ if p.peek() != eof {
+ if _, ok := val.(cfString); !ok {
+ p.error("garbage after end of document")
+ }
+
+ p.start = 0
+ p.pos = 0
+ val = p.parseDictionary(true)
+ }
+
+ pval = val
+
+ return
+}
+
+const eof rune = -1
+
+func (p *textPlistParser) error(e string, args ...interface{}) {
+ line := strings.Count(p.input[:p.pos], "\n")
+ char := p.pos - strings.LastIndex(p.input[:p.pos], "\n") - 1
+ panic(fmt.Errorf("%s at line %d character %d", fmt.Sprintf(e, args...), line, char))
+}
+
+func (p *textPlistParser) next() rune {
+ if int(p.pos) >= len(p.input) {
+ p.width = 0
+ return eof
+ }
+ r, w := utf8.DecodeRuneInString(p.input[p.pos:])
+ p.width = w
+ p.pos += p.width
+ return r
+}
+
+func (p *textPlistParser) backup() {
+ p.pos -= p.width
+}
+
+func (p *textPlistParser) peek() rune {
+ r := p.next()
+ p.backup()
+ return r
+}
+
+func (p *textPlistParser) emit() string {
+ s := p.input[p.start:p.pos]
+ p.start = p.pos
+ return s
+}
+
+func (p *textPlistParser) ignore() {
+ p.start = p.pos
+}
+
+func (p *textPlistParser) empty() bool {
+ return p.start == p.pos
+}
+
+func (p *textPlistParser) scanUntil(ch rune) {
+ if x := strings.IndexRune(p.input[p.pos:], ch); x >= 0 {
+ p.pos += x
+ return
+ }
+ p.pos = len(p.input)
+}
+
+func (p *textPlistParser) scanUntilAny(chs string) {
+ if x := strings.IndexAny(p.input[p.pos:], chs); x >= 0 {
+ p.pos += x
+ return
+ }
+ p.pos = len(p.input)
+}
+
+func (p *textPlistParser) scanCharactersInSet(ch *characterSet) {
+ for ch.Contains(p.next()) {
+ }
+ p.backup()
+}
+
+func (p *textPlistParser) scanCharactersNotInSet(ch *characterSet) {
+ var r rune
+ for {
+ r = p.next()
+ if r == eof || ch.Contains(r) {
+ break
+ }
+ }
+ p.backup()
+}
+
+func (p *textPlistParser) skipWhitespaceAndComments() {
+ for {
+ p.scanCharactersInSet(&whitespace)
+ if strings.HasPrefix(p.input[p.pos:], "//") {
+ p.scanCharactersNotInSet(&newlineCharacterSet)
+ } else if strings.HasPrefix(p.input[p.pos:], "/*") {
+ if x := strings.Index(p.input[p.pos:], "*/"); x >= 0 {
+ p.pos += x + 2 // skip the */ as well
+ continue // consume more whitespace
+ } else {
+ p.error("unexpected eof in block comment")
+ }
+ } else {
+ break
+ }
+ }
+ p.ignore()
+}
+
+func (p *textPlistParser) parseOctalDigits(max int) uint64 {
+ var val uint64
+
+ for i := 0; i < max; i++ {
+ r := p.next()
+
+ if r >= '0' && r <= '7' {
+ val <<= 3
+ val |= uint64((r - '0'))
+ } else {
+ p.backup()
+ break
+ }
+ }
+ return val
+}
+
+func (p *textPlistParser) parseHexDigits(max int) uint64 {
+ var val uint64
+
+ for i := 0; i < max; i++ {
+ r := p.next()
+
+ if r >= 'a' && r <= 'f' {
+ val <<= 4
+ val |= 10 + uint64((r - 'a'))
+ } else if r >= 'A' && r <= 'F' {
+ val <<= 4
+ val |= 10 + uint64((r - 'A'))
+ } else if r >= '0' && r <= '9' {
+ val <<= 4
+ val |= uint64((r - '0'))
+ } else {
+ p.backup()
+ break
+ }
+ }
+ return val
+}
+
+// the \ has already been consumed
+func (p *textPlistParser) parseEscape() string {
+ var s string
+ switch p.next() {
+ case 'a':
+ s = "\a"
+ case 'b':
+ s = "\b"
+ case 'v':
+ s = "\v"
+ case 'f':
+ s = "\f"
+ case 't':
+ s = "\t"
+ case 'r':
+ s = "\r"
+ case 'n':
+ s = "\n"
+ case '\\':
+ s = `\`
+ case '"':
+ s = `"`
+ case 'x':
+ s = string(rune(p.parseHexDigits(2)))
+ case 'u', 'U':
+ s = string(rune(p.parseHexDigits(4)))
+ case '0', '1', '2', '3', '4', '5', '6', '7':
+ p.backup() // we've already consumed one of the digits
+ s = string(rune(p.parseOctalDigits(3)))
+ default:
+ p.backup() // everything else should be accepted
+ }
+ p.ignore() // skip the entire escape sequence
+ return s
+}
+
+// the " has already been consumed
+func (p *textPlistParser) parseQuotedString() cfString {
+ p.ignore() // ignore the "
+
+ slowPath := false
+ s := ""
+
+ for {
+ p.scanUntilAny(`"\`)
+ switch p.peek() {
+ case eof:
+ p.error("unexpected eof in quoted string")
+ case '"':
+ section := p.emit()
+ p.pos++ // skip "
+ if !slowPath {
+ return cfString(section)
+ } else {
+ s += section
+ return cfString(s)
+ }
+ case '\\':
+ slowPath = true
+ s += p.emit()
+ p.next() // consume \
+ s += p.parseEscape()
+ }
+ }
+}
+
+func (p *textPlistParser) parseUnquotedString() cfString {
+ p.scanCharactersNotInSet(&gsQuotable)
+ s := p.emit()
+ if s == "" {
+ p.error("invalid unquoted string (found an unquoted character that should be quoted?)")
+ }
+
+ return cfString(s)
+}
+
+// the { has already been consumed
+func (p *textPlistParser) parseDictionary(ignoreEof bool) *cfDictionary {
+ //p.ignore() // ignore the {
+ var keypv cfValue
+ keys := make([]string, 0, 32)
+ values := make([]cfValue, 0, 32)
+outer:
+ for {
+ p.skipWhitespaceAndComments()
+
+ switch p.next() {
+ case eof:
+ if !ignoreEof {
+ p.error("unexpected eof in dictionary")
+ }
+ fallthrough
+ case '}':
+ break outer
+ case '"':
+ keypv = p.parseQuotedString()
+ default:
+ p.backup()
+ keypv = p.parseUnquotedString()
+ }
+
+ // INVARIANT: key can't be nil; parseQuoted and parseUnquoted
+ // will panic out before they return nil.
+
+ p.skipWhitespaceAndComments()
+
+ var val cfValue
+ n := p.next()
+ if n == ';' {
+ val = keypv
+ } else if n == '=' {
+ // whitespace is consumed within
+ val = p.parsePlistValue()
+
+ p.skipWhitespaceAndComments()
+
+ if p.next() != ';' {
+ p.error("missing ; in dictionary")
+ }
+ } else {
+ p.error("missing = in dictionary")
+ }
+
+ keys = append(keys, string(keypv.(cfString)))
+ values = append(values, val)
+ }
+
+ return &cfDictionary{keys: keys, values: values}
+}
+
+// the ( has already been consumed
+func (p *textPlistParser) parseArray() *cfArray {
+ //p.ignore() // ignore the (
+ values := make([]cfValue, 0, 32)
+outer:
+ for {
+ p.skipWhitespaceAndComments()
+
+ switch p.next() {
+ case eof:
+ p.error("unexpected eof in array")
+ case ')':
+ break outer // done here
+ case ',':
+ continue // restart; ,) is valid and we don't want to blow it
+ default:
+ p.backup()
+ }
+
+ pval := p.parsePlistValue() // whitespace is consumed within
+ if str, ok := pval.(cfString); ok && string(str) == "" {
+ // Empty strings in arrays are apparently skipped?
+ // TODO: Figure out why this was implemented.
+ continue
+ }
+ values = append(values, pval)
+ }
+ return &cfArray{values}
+}
+
+// the <* have already been consumed
+func (p *textPlistParser) parseGNUStepValue() cfValue {
+ typ := p.next()
+ p.ignore()
+ p.scanUntil('>')
+
+ if typ == eof || typ == '>' || p.empty() || p.peek() == eof {
+ p.error("invalid GNUStep extended value")
+ }
+
+ v := p.emit()
+ p.next() // consume the >
+
+ switch typ {
+ case 'I':
+ if v[0] == '-' {
+ n := mustParseInt(v, 10, 64)
+ return &cfNumber{signed: true, value: uint64(n)}
+ } else {
+ n := mustParseUint(v, 10, 64)
+ return &cfNumber{signed: false, value: n}
+ }
+ case 'R':
+ n := mustParseFloat(v, 64)
+ return &cfReal{wide: true, value: n} // TODO(DH) 32/64
+ case 'B':
+ b := v[0] == 'Y'
+ return cfBoolean(b)
+ case 'D':
+ t, err := time.Parse(textPlistTimeLayout, v)
+ if err != nil {
+ p.error(err.Error())
+ }
+
+ return cfDate(t.In(time.UTC))
+ }
+ p.error("invalid GNUStep type " + string(typ))
+ return nil
+}
+
+// The < has already been consumed
+func (p *textPlistParser) parseHexData() cfData {
+ buf := make([]byte, 256)
+ i := 0
+ c := 0
+
+ for {
+ r := p.next()
+ switch r {
+ case eof:
+ p.error("unexpected eof in data")
+ case '>':
+ if c&1 == 1 {
+ p.error("uneven number of hex digits in data")
+ }
+ p.ignore()
+ return cfData(buf[:i])
+ case ' ', '\t', '\n', '\r', '\u2028', '\u2029': // more lax than apple here: skip spaces
+ continue
+ }
+
+ buf[i] <<= 4
+ if r >= 'a' && r <= 'f' {
+ buf[i] |= 10 + byte((r - 'a'))
+ } else if r >= 'A' && r <= 'F' {
+ buf[i] |= 10 + byte((r - 'A'))
+ } else if r >= '0' && r <= '9' {
+ buf[i] |= byte((r - '0'))
+ } else {
+ p.error("unexpected hex digit `%c'", r)
+ }
+
+ c++
+ if c&1 == 0 {
+ i++
+ if i >= len(buf) {
+ realloc := make([]byte, len(buf)*2)
+ copy(realloc, buf)
+ buf = realloc
+ }
+ }
+ }
+}
+
+func (p *textPlistParser) parsePlistValue() cfValue {
+ for {
+ p.skipWhitespaceAndComments()
+
+ switch p.next() {
+ case eof:
+ return &cfDictionary{}
+ case '<':
+ if p.next() == '*' {
+ p.format = GNUStepFormat
+ return p.parseGNUStepValue()
+ }
+
+ p.backup()
+ return p.parseHexData()
+ case '"':
+ return p.parseQuotedString()
+ case '{':
+ return p.parseDictionary(false)
+ case '(':
+ return p.parseArray()
+ default:
+ p.backup()
+ return p.parseUnquotedString()
+ }
+ }
+}
+
+func newTextPlistParser(r io.Reader) *textPlistParser {
+ return &textPlistParser{
+ reader: r,
+ format: OpenStepFormat,
+ }
+}
diff --git a/vendor/github.com/DHowett/go-plist/text_tables.go b/vendor/howett.net/plist/text_tables.go
similarity index 55%
rename from vendor/github.com/DHowett/go-plist/text_tables.go
rename to vendor/howett.net/plist/text_tables.go
index ec6586b0..319c55c5 100644
--- a/vendor/github.com/DHowett/go-plist/text_tables.go
+++ b/vendor/howett.net/plist/text_tables.go
@@ -1,9 +1,19 @@
package plist
+type characterSet [4]uint64
+
+func (s *characterSet) Contains(ch rune) bool {
+ return ch >= 0 && ch <= 255 && s.ContainsByte(byte(ch))
+}
+
+func (s *characterSet) ContainsByte(ch byte) bool {
+ return (s[ch/64]&(1<<(ch%64)) > 0)
+}
+
// 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{
+var gsQuotable = characterSet{
0x78001385ffffffff,
0xa800000138000000,
0xffffffffffffffff,
@@ -11,16 +21,23 @@ var gsQuotable = [4]uint64{
}
// 7f instead of 3f in the top line: CFOldStylePlist.c says . is valid, but they quote it.
-var osQuotable = [4]uint64{
+var osQuotable = characterSet{
0xf4007f6fffffffff,
0xf8000001f8000001,
0xffffffffffffffff,
0xffffffffffffffff,
}
-var whitespace = [4]uint64{
+var whitespace = characterSet{
0x0000000100003f00,
0x0000000000000000,
0x0000000000000000,
0x0000000000000000,
}
+
+var newlineCharacterSet = characterSet{
+ 0x0000000000002400,
+ 0x0000000000000000,
+ 0x0000000000000000,
+ 0x0000000000000000,
+}
diff --git a/vendor/github.com/DHowett/go-plist/typeinfo.go b/vendor/howett.net/plist/typeinfo.go
similarity index 100%
rename from vendor/github.com/DHowett/go-plist/typeinfo.go
rename to vendor/howett.net/plist/typeinfo.go
diff --git a/vendor/howett.net/plist/unmarshal.go b/vendor/howett.net/plist/unmarshal.go
new file mode 100644
index 00000000..e38cbe53
--- /dev/null
+++ b/vendor/howett.net/plist/unmarshal.go
@@ -0,0 +1,320 @@
+package plist
+
+import (
+ "encoding"
+ "fmt"
+ "reflect"
+ "runtime"
+ "time"
+)
+
+type incompatibleDecodeTypeError struct {
+ dest reflect.Type
+ src string // type name (from cfValue)
+}
+
+func (u *incompatibleDecodeTypeError) Error() string {
+ return fmt.Sprintf("plist: type mismatch: tried to decode plist type `%v' into value of type `%v'", u.src, u.dest)
+}
+
+var (
+ plistUnmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
+ textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
+ uidType = reflect.TypeOf(UID(0))
+)
+
+func isEmptyInterface(v reflect.Value) bool {
+ return v.Kind() == reflect.Interface && v.NumMethod() == 0
+}
+
+func (p *Decoder) unmarshalPlistInterface(pval cfValue, unmarshalable Unmarshaler) {
+ err := unmarshalable.UnmarshalPlist(func(i interface{}) (err error) {
+ defer func() {
+ if r := recover(); r != nil {
+ if _, ok := r.(runtime.Error); ok {
+ panic(r)
+ }
+ err = r.(error)
+ }
+ }()
+ p.unmarshal(pval, reflect.ValueOf(i))
+ return
+ })
+
+ if err != nil {
+ panic(err)
+ }
+}
+
+func (p *Decoder) unmarshalTextInterface(pval cfString, unmarshalable encoding.TextUnmarshaler) {
+ err := unmarshalable.UnmarshalText([]byte(pval))
+ if err != nil {
+ panic(err)
+ }
+}
+
+func (p *Decoder) unmarshalTime(pval cfDate, val reflect.Value) {
+ val.Set(reflect.ValueOf(time.Time(pval)))
+}
+
+func (p *Decoder) unmarshalLaxString(s string, val reflect.Value) {
+ switch val.Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ i := mustParseInt(s, 10, 64)
+ val.SetInt(i)
+ return
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ i := mustParseUint(s, 10, 64)
+ val.SetUint(i)
+ return
+ case reflect.Float32, reflect.Float64:
+ f := mustParseFloat(s, 64)
+ val.SetFloat(f)
+ return
+ case reflect.Bool:
+ b := mustParseBool(s)
+ val.SetBool(b)
+ return
+ case reflect.Struct:
+ if val.Type() == timeType {
+ t, err := time.Parse(textPlistTimeLayout, s)
+ if err != nil {
+ panic(err)
+ }
+ val.Set(reflect.ValueOf(t.In(time.UTC)))
+ return
+ }
+ fallthrough
+ default:
+ panic(&incompatibleDecodeTypeError{val.Type(), "string"})
+ }
+}
+
+func (p *Decoder) unmarshal(pval cfValue, val reflect.Value) {
+ if pval == nil {
+ return
+ }
+
+ if val.Kind() == reflect.Ptr {
+ if val.IsNil() {
+ val.Set(reflect.New(val.Type().Elem()))
+ }
+ val = val.Elem()
+ }
+
+ if isEmptyInterface(val) {
+ v := p.valueInterface(pval)
+ val.Set(reflect.ValueOf(v))
+ return
+ }
+
+ incompatibleTypeError := &incompatibleDecodeTypeError{val.Type(), pval.typeName()}
+
+ // time.Time implements TextMarshaler, but we need to parse it as RFC3339
+ if date, ok := pval.(cfDate); ok {
+ if val.Type() == timeType {
+ p.unmarshalTime(date, val)
+ return
+ }
+ panic(incompatibleTypeError)
+ }
+
+ if receiver, can := implementsInterface(val, plistUnmarshalerType); can {
+ p.unmarshalPlistInterface(pval, receiver.(Unmarshaler))
+ return
+ }
+
+ if val.Type() != timeType {
+ if receiver, can := implementsInterface(val, textUnmarshalerType); can {
+ if str, ok := pval.(cfString); ok {
+ p.unmarshalTextInterface(str, receiver.(encoding.TextUnmarshaler))
+ } else {
+ panic(incompatibleTypeError)
+ }
+ return
+ }
+ }
+
+ typ := val.Type()
+
+ switch pval := pval.(type) {
+ case cfString:
+ if val.Kind() == reflect.String {
+ val.SetString(string(pval))
+ return
+ }
+ if p.lax {
+ p.unmarshalLaxString(string(pval), val)
+ return
+ }
+
+ panic(incompatibleTypeError)
+ case *cfNumber:
+ switch val.Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ val.SetInt(int64(pval.value))
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ val.SetUint(pval.value)
+ default:
+ panic(incompatibleTypeError)
+ }
+ case *cfReal:
+ if val.Kind() == reflect.Float32 || val.Kind() == reflect.Float64 {
+ // TODO: Consider warning on a downcast (storing a 64-bit value in a 32-bit reflect)
+ val.SetFloat(pval.value)
+ } else {
+ panic(incompatibleTypeError)
+ }
+ case cfBoolean:
+ if val.Kind() == reflect.Bool {
+ val.SetBool(bool(pval))
+ } else {
+ panic(incompatibleTypeError)
+ }
+ case cfData:
+ if val.Kind() == reflect.Slice && typ.Elem().Kind() == reflect.Uint8 {
+ val.SetBytes([]byte(pval))
+ } else {
+ panic(incompatibleTypeError)
+ }
+ case cfUID:
+ if val.Type() == uidType {
+ val.SetUint(uint64(pval))
+ } else {
+ switch val.Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ val.SetInt(int64(pval))
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ val.SetUint(uint64(pval))
+ default:
+ panic(incompatibleTypeError)
+ }
+ }
+ case *cfArray:
+ p.unmarshalArray(pval, val)
+ case *cfDictionary:
+ p.unmarshalDictionary(pval, val)
+ }
+}
+
+func (p *Decoder) unmarshalArray(a *cfArray, val reflect.Value) {
+ var n int
+ if val.Kind() == reflect.Slice {
+ // Slice of element values.
+ // Grow slice.
+ cnt := len(a.values) + val.Len()
+ if cnt >= val.Cap() {
+ ncap := 2 * cnt
+ if ncap < 4 {
+ ncap = 4
+ }
+ new := reflect.MakeSlice(val.Type(), val.Len(), ncap)
+ reflect.Copy(new, val)
+ val.Set(new)
+ }
+ n = val.Len()
+ val.SetLen(cnt)
+ } else if val.Kind() == reflect.Array {
+ if len(a.values) > val.Cap() {
+ panic(fmt.Errorf("plist: attempted to unmarshal %d values into an array of size %d", len(a.values), val.Cap()))
+ }
+ } else {
+ panic(&incompatibleDecodeTypeError{val.Type(), a.typeName()})
+ }
+
+ // Recur to read element into slice.
+ for _, sval := range a.values {
+ p.unmarshal(sval, val.Index(n))
+ n++
+ }
+ return
+}
+
+func (p *Decoder) unmarshalDictionary(dict *cfDictionary, val reflect.Value) {
+ typ := val.Type()
+ switch val.Kind() {
+ case reflect.Struct:
+ tinfo, err := getTypeInfo(typ)
+ if err != nil {
+ panic(err)
+ }
+
+ entries := make(map[string]cfValue, len(dict.keys))
+ for i, k := range dict.keys {
+ sval := dict.values[i]
+ entries[k] = sval
+ }
+
+ for _, finfo := range tinfo.fields {
+ p.unmarshal(entries[finfo.name], finfo.value(val))
+ }
+ case reflect.Map:
+ if val.IsNil() {
+ val.Set(reflect.MakeMap(typ))
+ }
+
+ for i, k := range dict.keys {
+ sval := dict.values[i]
+
+ keyv := reflect.ValueOf(k).Convert(typ.Key())
+ mapElem := val.MapIndex(keyv)
+ if !mapElem.IsValid() {
+ mapElem = reflect.New(typ.Elem()).Elem()
+ }
+
+ p.unmarshal(sval, mapElem)
+ val.SetMapIndex(keyv, mapElem)
+ }
+ default:
+ panic(&incompatibleDecodeTypeError{typ, dict.typeName()})
+ }
+}
+
+/* *Interface is modelled after encoding/json */
+func (p *Decoder) valueInterface(pval cfValue) interface{} {
+ switch pval := pval.(type) {
+ case cfString:
+ return string(pval)
+ case *cfNumber:
+ if pval.signed {
+ return int64(pval.value)
+ }
+ return pval.value
+ case *cfReal:
+ if pval.wide {
+ return pval.value
+ } else {
+ return float32(pval.value)
+ }
+ case cfBoolean:
+ return bool(pval)
+ case *cfArray:
+ return p.arrayInterface(pval)
+ case *cfDictionary:
+ return p.dictionaryInterface(pval)
+ case cfData:
+ return []byte(pval)
+ case cfDate:
+ return time.Time(pval)
+ case cfUID:
+ return UID(pval)
+ }
+ return nil
+}
+
+func (p *Decoder) arrayInterface(a *cfArray) []interface{} {
+ out := make([]interface{}, len(a.values))
+ for i, subv := range a.values {
+ out[i] = p.valueInterface(subv)
+ }
+ return out
+}
+
+func (p *Decoder) dictionaryInterface(dict *cfDictionary) map[string]interface{} {
+ out := make(map[string]interface{})
+ for i, k := range dict.keys {
+ subv := dict.values[i]
+ out[k] = p.valueInterface(subv)
+ }
+ return out
+}
diff --git a/vendor/github.com/DHowett/go-plist/util.go b/vendor/howett.net/plist/util.go
similarity index 100%
rename from vendor/github.com/DHowett/go-plist/util.go
rename to vendor/howett.net/plist/util.go
diff --git a/vendor/github.com/DHowett/go-plist/xml.go b/vendor/howett.net/plist/xml.go
similarity index 68%
rename from vendor/github.com/DHowett/go-plist/xml.go
rename to vendor/howett.net/plist/xml.go
index 17090c14..91cfeaa6 100644
--- a/vendor/github.com/DHowett/go-plist/xml.go
+++ b/vendor/howett.net/plist/xml.go
@@ -20,7 +20,7 @@ type xmlPlistGenerator struct {
xmlEncoder *xml.Encoder
}
-func (p *xmlPlistGenerator) generateDocument(pval *plistValue) {
+func (p *xmlPlistGenerator) generateDocument(root cfValue) {
io.WriteString(p.writer, xml.Header)
io.WriteString(p.writer, xmlDOCTYPE)
@@ -39,74 +39,98 @@ func (p *xmlPlistGenerator) generateDocument(pval *plistValue) {
p.xmlEncoder.EncodeToken(plistStartElement)
- p.writePlistValue(pval)
+ p.writePlistValue(root)
p.xmlEncoder.EncodeToken(plistStartElement.End())
p.xmlEncoder.Flush()
}
-func (p *xmlPlistGenerator) writePlistValue(pval *plistValue) {
+func (p *xmlPlistGenerator) writeDictionary(dict *cfDictionary) {
+ dict.sort()
+ startElement := xml.StartElement{Name: xml.Name{Local: "dict"}}
+ p.xmlEncoder.EncodeToken(startElement)
+ 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())
+}
+
+func (p *xmlPlistGenerator) writeArray(a *cfArray) {
+ startElement := xml.StartElement{Name: xml.Name{Local: "array"}}
+ p.xmlEncoder.EncodeToken(startElement)
+ for _, v := range a.values {
+ p.writePlistValue(v)
+ }
+ p.xmlEncoder.EncodeToken(startElement.End())
+}
+
+func (p *xmlPlistGenerator) writePlistValue(pval cfValue) {
if pval == nil {
return
}
defer p.xmlEncoder.Flush()
+ if dict, ok := pval.(*cfDictionary); ok {
+ p.writeDictionary(dict)
+ return
+ } else if a, ok := pval.(*cfArray); ok {
+ p.writeArray(a)
+ return
+ } else if uid, ok := pval.(cfUID); ok {
+ p.writeDictionary(&cfDictionary{
+ keys: []string{"CF$UID"},
+ values: []cfValue{
+ &cfNumber{
+ signed: false,
+ value: uint64(uid),
+ },
+ },
+ })
+ return
+ }
+
+ // Everything here and beyond is encoded the same way: value
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:
+ var encodedValue interface{} = pval
+
+ switch pval := pval.(type) {
+ case cfString:
key = "string"
- case Integer:
+ case *cfNumber:
key = "integer"
- if pval.value.(signedInt).signed {
- encodedValue = int64(pval.value.(signedInt).value)
+ if pval.signed {
+ encodedValue = int64(pval.value)
} else {
- encodedValue = pval.value.(signedInt).value
+ encodedValue = pval.value
}
- case Real:
+ case *cfReal:
key = "real"
- encodedValue = pval.value.(sizedFloat).value
+ encodedValue = pval.value
switch {
- case math.IsInf(pval.value.(sizedFloat).value, 1):
+ case math.IsInf(pval.value, 1):
encodedValue = "inf"
- case math.IsInf(pval.value.(sizedFloat).value, -1):
+ case math.IsInf(pval.value, -1):
encodedValue = "-inf"
- case math.IsNaN(pval.value.(sizedFloat).value):
+ case math.IsNaN(pval.value):
encodedValue = "nan"
}
- case Boolean:
+ case cfBoolean:
key = "false"
- b := pval.value.(bool)
+ b := bool(pval)
if b {
key = "true"
}
encodedValue = ""
- case Data:
+ case cfData:
key = "data"
- encodedValue = xml.CharData(base64.StdEncoding.EncodeToString(pval.value.([]byte)))
- case Date:
+ encodedValue = xml.CharData(base64.StdEncoding.EncodeToString([]byte(pval)))
+ case cfDate:
key = "date"
- encodedValue = pval.value.(time.Time).In(time.UTC).Format(time.RFC3339)
+ encodedValue = time.Time(pval).In(time.UTC).Format(time.RFC3339)
}
+
if key != "" {
err := p.xmlEncoder.EncodeElement(encodedValue, xml.StartElement{Name: xml.Name{Local: key}})
if err != nil {
@@ -131,7 +155,7 @@ type xmlPlistParser struct {
ntags int
}
-func (p *xmlPlistParser) parseDocument() (pval *plistValue, parseError error) {
+func (p *xmlPlistParser) parseDocument() (pval cfValue, parseError error) {
defer func() {
if r := recover(); r != nil {
if _, ok := r.(runtime.Error); ok {
@@ -162,7 +186,7 @@ func (p *xmlPlistParser) parseDocument() (pval *plistValue, parseError error) {
}
}
-func (p *xmlPlistParser) parseXMLElement(element xml.StartElement) *plistValue {
+func (p *xmlPlistParser) parseXMLElement(element xml.StartElement) cfValue {
var charData xml.CharData
switch element.Name.Local {
case "plist":
@@ -189,7 +213,7 @@ func (p *xmlPlistParser) parseXMLElement(element xml.StartElement) *plistValue {
panic(err)
}
- return &plistValue{String, string(charData)}
+ return cfString(charData)
case "integer":
p.ntags++
err := p.xmlDecoder.DecodeElement(&charData, &element)
@@ -205,11 +229,11 @@ func (p *xmlPlistParser) parseXMLElement(element xml.StartElement) *plistValue {
if s[0] == '-' {
s, base := unsignedGetBase(s[1:])
n := mustParseInt("-"+s, base, 64)
- return &plistValue{Integer, signedInt{uint64(n), true}}
+ return &cfNumber{signed: true, value: uint64(n)}
} else {
s, base := unsignedGetBase(s)
n := mustParseUint(s, base, 64)
- return &plistValue{Integer, signedInt{n, false}}
+ return &cfNumber{signed: false, value: n}
}
case "real":
p.ntags++
@@ -219,13 +243,13 @@ func (p *xmlPlistParser) parseXMLElement(element xml.StartElement) *plistValue {
}
n := mustParseFloat(string(charData), 64)
- return &plistValue{Real, sizedFloat{n, 64}}
+ return &cfReal{wide: true, value: n}
case "true", "false":
p.ntags++
p.xmlDecoder.Skip()
b := element.Name.Local == "true"
- return &plistValue{Boolean, b}
+ return cfBoolean(b)
case "date":
p.ntags++
err := p.xmlDecoder.DecodeElement(&charData, &element)
@@ -238,7 +262,7 @@ func (p *xmlPlistParser) parseXMLElement(element xml.StartElement) *plistValue {
panic(err)
}
- return &plistValue{Date, t}
+ return cfDate(t)
case "data":
p.ntags++
err := p.xmlDecoder.DecodeElement(&charData, &element)
@@ -255,11 +279,12 @@ func (p *xmlPlistParser) parseXMLElement(element xml.StartElement) *plistValue {
panic(err)
}
- return &plistValue{Data, bytes[:l]}
+ return cfData(bytes[:l])
case "dict":
p.ntags++
var key *string
- var subvalues map[string]*plistValue = make(map[string]*plistValue)
+ keys := make([]string, 0, 32)
+ values := make([]cfValue, 0, 32)
for {
token, err := p.xmlDecoder.Token()
if err != nil {
@@ -282,15 +307,23 @@ func (p *xmlPlistParser) parseXMLElement(element xml.StartElement) *plistValue {
if key == nil {
panic(errors.New("missing key in dictionary"))
}
- subvalues[*key] = p.parseXMLElement(el)
+ keys = append(keys, *key)
+ values = append(values, p.parseXMLElement(el))
key = nil
}
}
}
- return &plistValue{Dictionary, &dictionary{m: subvalues}}
+
+ if len(keys) == 1 && keys[0] == "CF$UID" && len(values) == 1 {
+ if integer, ok := values[0].(*cfNumber); ok {
+ return cfUID(integer.value)
+ }
+ }
+
+ return &cfDictionary{keys: keys, values: values}
case "array":
p.ntags++
- var subvalues []*plistValue = make([]*plistValue, 0, 10)
+ values := make([]cfValue, 0, 10)
for {
token, err := p.xmlDecoder.Token()
if err != nil {
@@ -302,10 +335,10 @@ func (p *xmlPlistParser) parseXMLElement(element xml.StartElement) *plistValue {
}
if el, ok := token.(xml.StartElement); ok {
- subvalues = append(subvalues, p.parseXMLElement(el))
+ values = append(values, p.parseXMLElement(el))
}
}
- return &plistValue{Array, subvalues}
+ return &cfArray{values}
}
err := fmt.Errorf("encountered unknown element %s", element.Name.Local)
if p.ntags == 0 {
diff --git a/vendor/howett.net/plist/zerocopy.go b/vendor/howett.net/plist/zerocopy.go
new file mode 100644
index 00000000..999f401b
--- /dev/null
+++ b/vendor/howett.net/plist/zerocopy.go
@@ -0,0 +1,20 @@
+// +build !appengine
+
+package plist
+
+import (
+ "reflect"
+ "unsafe"
+)
+
+func zeroCopy8BitString(buf []byte, off int, len int) string {
+ if len == 0 {
+ return ""
+ }
+
+ var s string
+ hdr := (*reflect.StringHeader)(unsafe.Pointer(&s))
+ hdr.Data = uintptr(unsafe.Pointer(&buf[off]))
+ hdr.Len = len
+ return s
+}
diff --git a/vendor/howett.net/plist/zerocopy_appengine.go b/vendor/howett.net/plist/zerocopy_appengine.go
new file mode 100644
index 00000000..dbd9a1ac
--- /dev/null
+++ b/vendor/howett.net/plist/zerocopy_appengine.go
@@ -0,0 +1,7 @@
+// +build appengine
+
+package plist
+
+func zeroCopy8BitString(buf []byte, off int, len int) string {
+ return string(buf[off : off+len])
+}