├── .gitignore
├── LICENSE
├── Makefile
├── README.md
├── VERSION
├── img
└── livedic.png
├── resources
├── DictionaryOff.png
└── DictionaryOn.png
├── src
├── Info.plist
├── actionUrl.js
└── dict
│ ├── lookup.go
│ └── main.go
└── vendor
├── manifest
└── src
└── github.com
├── DHowett
└── go-plist
│ ├── LICENSE
│ ├── README.md
│ ├── bplist.go
│ ├── bplist_test.go
│ ├── common_data_for_test.go
│ ├── decode.go
│ ├── decode_test.go
│ ├── doc.go
│ ├── encode.go
│ ├── encode_test.go
│ ├── marshal.go
│ ├── marshal_test.go
│ ├── must.go
│ ├── plist.go
│ ├── text.go
│ ├── text_tables.go
│ ├── text_test.go
│ ├── typeinfo.go
│ ├── unmarshal.go
│ ├── unmarshal_test.go
│ ├── util.go
│ ├── xml.go
│ └── xml_test.go
├── bitly
└── go-simplejson
│ ├── .travis.yml
│ ├── LICENSE
│ ├── README.md
│ ├── simplejson.go
│ ├── simplejson_go10.go
│ ├── simplejson_go10_test.go
│ ├── simplejson_go11.go
│ ├── simplejson_go11_test.go
│ └── simplejson_test.go
├── codegangsta
└── inject
│ ├── .gitignore
│ ├── LICENSE
│ ├── README.md
│ ├── inject.go
│ └── inject_test.go
└── nbjahan
└── go-launchbar
├── LICENSE
├── README.md
├── cache.go
├── config.go
├── context.go
├── input.go
├── item.go
├── items.go
├── launchbar.go
├── update.go
├── version.go
├── version_test.go
└── view.go
/.gitignore:
--------------------------------------------------------------------------------
1 | dist
2 | bin
3 | pkg
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2014 nbjahan - https://github.com/nbjahan/launchbar-livedic
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
20 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | SHELL = /bin/bash
2 | DESTDIR = ./dist
3 |
4 | RELEASE_BASENAME = Dictionary.Live
5 | BUNDLE_NAME = Dictionary\:\ Define\ \(Live\)
6 | BUNDLE_VERSION = $(shell cat VERSION)
7 | BUNDLE_IDENTIFIER = nbjahan.launchbar.livedic
8 | BUNDLE_ICON = com.apple.Dictionary
9 | AUTHOR = nbjahan
10 | TWITTER = @nbjahan
11 | SLUG = launchbar-livedic
12 | WEBSITE = http://github.com/nbjahan/$(SLUG)
13 | SCRIPT_NAME = dict
14 |
15 | LBACTION_PATH = $(DESTDIR)/$(RELEASE_BASENAME).lbaction
16 | RELEASE_FILENAME = $(RELEASE_BASENAME)-$(BUNDLE_VERSION).lbaction
17 | LDFLAGS=
18 |
19 | UPDATE_LINK = https://raw.githubusercontent.com/nbjahan/$(SLUG)/master/src/Info.plist
20 | DOWNLOAD_LINK = https://github.com/nbjahan/$(SLUG)/releases/download/v$(BUNDLE_VERSION)/$(RELEASE_FILENAME)
21 | all:
22 | @$(RM) -rf $(DESTDIR)
23 |
24 | @install -d ${LBACTION_PATH}/Contents/{Resources,Scripts}
25 | @plutil -replace CFBundleName -string $(BUNDLE_NAME) $(PWD)/src/Info.plist
26 | @plutil -replace CFBundleVersion -string $(BUNDLE_VERSION) $(PWD)/src/Info.plist
27 | @plutil -replace CFBundleIdentifier -string $(BUNDLE_IDENTIFIER) $(PWD)/src/Info.plist
28 | @plutil -replace CFBundleIconFile -string $(BUNDLE_ICON) $(PWD)/src/Info.plist
29 | @plutil -replace LBDescription.LBAuthor -string $(AUTHOR) $(PWD)/src/Info.plist
30 | @plutil -replace LBDescription.LBTwitter -string $(TWITTER) $(PWD)/src/Info.plist
31 | @plutil -replace LBDescription.LBWebsiteURL -string $(WEBSITE) $(PWD)/src/Info.plist
32 | @plutil -replace LBDescription.LBUpdateURL -string $(UPDATE_LINK) $(PWD)/src/Info.plist
33 | @plutil -replace LBDescription.LBDownloadURL -string $(DOWNLOAD_LINK) $(PWD)/src/Info.plist
34 | @plutil -replace LBScripts.LBDefaultScript.LBScriptName -string $(SCRIPT_NAME) $(PWD)/src/Info.plist
35 | @install -pm 0644 ./src/Info.plist $(LBACTION_PATH)/Contents/
36 | gb build $(LDFLAGS) $(SCRIPT_NAME) && mv bin/$(SCRIPT_NAME) $(LBACTION_PATH)/Contents/Scripts/
37 | -@cp -f ./src/*.js $(LBACTION_PATH)/Contents/Scripts/
38 | -@cp -rf ./resources/* $(LBACTION_PATH)/Contents/Resources/
39 |
40 | @echo "Refreshing the LaunchBar"
41 | @osascript -e 'run script "tell application \"LaunchBar\" \n repeat with rule in indexing rules \n if name of rule is \"Actions\" then \n update rule \n exit repeat \n end if \n end repeat \n activate \n end tell"'
42 |
43 | @echo "Making a release"
44 | @install -d $(DESTDIR)/release
45 | @ditto -ck --keepParent $(LBACTION_PATH)/ $(DESTDIR)/release/$(RELEASE_FILENAME)
46 |
47 | dev: LDFLAGS := -ldflags "-X main.InDev true"
48 | dev: all
49 |
50 | release: all
51 |
52 | .PHONY: all dev
53 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Live search in Dictionary.app
2 | ===
3 |
4 | 
5 |
6 | ## Features
7 |
8 | - Very Fast
9 | - Live results
10 | - Spell checking
11 | - Automatic update checks.
12 |
13 | ## URL Scheme
14 |
15 | `open "x-launchbar:action/nbjahan.launchbar.livedic/lookup?hello"`
16 |
17 | ## Secrets
18 |
19 | - `⇧+Enter` to paste the selected word in the frontmost application.
20 | - `⌃+Enter` to pass the exact query to _Dictionary.app_
21 |
22 | ## Download
23 |
24 | Get the latest version from: https://github.com/nbjahan/launchbar-livedic/releases/latest
25 |
26 | ## License
27 |
28 | >MIT
--------------------------------------------------------------------------------
/VERSION:
--------------------------------------------------------------------------------
1 | 1.2.0
--------------------------------------------------------------------------------
/img/livedic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nbjahan/launchbar-livedic/e318d3264c1d204f95027d44187c27c9f70d6171/img/livedic.png
--------------------------------------------------------------------------------
/resources/DictionaryOff.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nbjahan/launchbar-livedic/e318d3264c1d204f95027d44187c27c9f70d6171/resources/DictionaryOff.png
--------------------------------------------------------------------------------
/resources/DictionaryOn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nbjahan/launchbar-livedic/e318d3264c1d204f95027d44187c27c9f70d6171/resources/DictionaryOn.png
--------------------------------------------------------------------------------
/src/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleIconFile
6 | com.apple.Dictionary
7 | CFBundleIdentifier
8 | nbjahan.launchbar.livedic
9 | CFBundleName
10 | Dictionary: Define (Live)
11 | CFBundleVersion
12 | 1.2.0
13 | LBAssociatedApplication
14 | com.apple.Dictionary
15 | LBDebugLogEnabled
16 |
17 | LBDescription
18 |
19 | LBAuthor
20 | nbjahan
21 | LBChangelog
22 |
23 | Fixed unicode lookup (thanks to @blahgeek)
24 | Added support for @prenagha's Action Updates
25 | Added support for LaunchBar URL scheme
26 | x-launchbar:action/nbjahan.launchbar.livedic/lookup?YOUR_QUERY_STRING
27 |
28 |
29 |
30 | LBDownload
31 | https://github.com/nbjahan/launchbar-livedic/releases/download/v1.2.0/Dictionary.Live-1.2.0.lbaction
32 |
33 |
34 | LBUpdate
35 | https://raw.githubusercontent.com/nbjahan/launchbar-livedic/master/src/Info.plist
36 |
37 | LBDownloadURL
38 | https://github.com/nbjahan/launchbar-livedic/releases/download/v1.2.0/Dictionary.Live-1.2.0.lbaction
39 | LBResult
40 | List of auto corrected words for the current query.
41 | LBSummary
42 | Live search in Dictionary.app with auto correction. Hold ⌃ to pass the exact query. Hold ⇧ to paste the item in the frontmost app.
43 | LBTwitter
44 | @nbjahan
45 | LBUpdateURL
46 | https://raw.githubusercontent.com/nbjahan/launchbar-livedic/master/src/Info.plist
47 | LBWebsiteURL
48 | http://github.com/nbjahan/launchbar-livedic
49 |
50 | LBRequiredApplication
51 | com.apple.Dictionary
52 | LBScripts
53 |
54 | LBActionURLScript
55 |
56 | LBRunInBackground
57 |
58 | LBScriptName
59 | actionUrl.js
60 |
61 | LBDefaultScript
62 |
63 | LBKeepWindowActive
64 |
65 | LBLiveFeedbackEnabled
66 |
67 | LBRequiresArgument
68 |
69 | LBScriptName
70 | dict
71 |
72 |
73 | LBTextInputTitle
74 | Define
75 | NSHumanReadableCopyright
76 | Copyright © 2016 nbjahan
77 |
78 |
79 |
--------------------------------------------------------------------------------
/src/actionUrl.js:
--------------------------------------------------------------------------------
1 | function runWithURL(url , details) {
2 | LaunchBar.log(JSON.stringify(details));
3 | var path = details.path.replace('/nbjahan.launchbar.livedic/', '');
4 | switch(path) {
5 | case 'lookup':
6 | var q = details.query;
7 | if (q && q.length > 0) {
8 | q = JSON.stringify(q).slice(1,-1);
9 | LaunchBar.performAction("Dictionary: Define (Live)", q);
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/src/dict/lookup.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | /*
4 | #cgo CFLAGS: -x objective-c
5 | #cgo LDFLAGS: -framework Cocoa -framework AppKit
6 | #import
7 | #import
8 |
9 | const char*
10 | define(const char *s, int *start, int *len) {
11 | NSString *word = [[NSString alloc] initWithCString:s encoding:NSUTF8StringEncoding];
12 | CFRange termRange = DCSGetTermRangeInString(NULL, (CFStringRef)word, 0);
13 |
14 | NSString *definition = @"";
15 | *start = termRange.location;
16 | *len = termRange.length;
17 |
18 | if(*start != -1) {
19 | definition = (NSString*)DCSCopyTextDefinition(NULL, (CFStringRef)word, termRange);
20 | NSString *first_part = [word substringToIndex: *start];
21 | NSString *second_part = [word substringWithRange: NSMakeRange(*start, *len)];
22 | *start = [first_part lengthOfBytesUsingEncoding: NSUTF8StringEncoding];
23 | *len = [second_part lengthOfBytesUsingEncoding: NSUTF8StringEncoding];
24 | }
25 |
26 | return [definition UTF8String];
27 | }
28 |
29 | const char **
30 | spell(const char * s, int *n) {
31 | NSString * term = [[NSString alloc] initWithCString:s encoding:NSUTF8StringEncoding];
32 | NSSpellChecker *spellChecker = [NSSpellChecker sharedSpellChecker];
33 | NSArray *guesses = [spellChecker guessesForWordRange:NSMakeRange(0, [term length])
34 | inString:term
35 | language:[spellChecker language]
36 | inSpellDocumentWithTag:0];
37 | int count = [guesses count];
38 | *n = count;
39 | const char** cArray = malloc(sizeof(const char *) * count);
40 | for (int i=0; i 0 {
98 | fields = fields[1:]
99 | }
100 | def = strings.Join(fields, " ")
101 | def = strings.TrimSpace(def)
102 | if def == "" {
103 | continue
104 | }
105 | definitions = append(definitions, []string{subword, def})
106 | limit -= 1
107 | }
108 |
109 | limit = len(definitions)
110 | out := make([][]string, limit+1)
111 | i := 0
112 | for _, row := range definitions {
113 | i++
114 | word := row[0]
115 | def := row[1]
116 | if out[0] == nil && word == q {
117 | out[0] = []string{q, def}
118 | continue
119 | }
120 | if i == limit+1 {
121 | break
122 | }
123 | out[i] = []string{word, def}
124 | }
125 |
126 | if out[0] == nil {
127 | word, def := define(q)
128 | if def != "" {
129 | out[0] = []string{word, def}
130 | } else {
131 | out = append(out[1:], []string{})
132 | }
133 | }
134 |
135 | return out[0 : len(out)-1]
136 | }
137 |
--------------------------------------------------------------------------------
/src/dict/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "net/url"
6 | "os"
7 | "os/exec"
8 | "reflect"
9 | "strings"
10 |
11 | "time"
12 |
13 | "github.com/DHowett/go-plist"
14 | sjson "github.com/bitly/go-simplejson"
15 | . "github.com/nbjahan/go-launchbar"
16 | )
17 |
18 | var InDev string
19 |
20 | var pb *Action
21 | var start = time.Now()
22 |
23 | var funcs = map[string]Func{
24 | "openDictionary": func(c *Context) {
25 | word := c.Input.FuncArg()
26 | if pb.IsControlKey() {
27 | word = c.Input.String()
28 | }
29 | if pb.IsShiftKey() {
30 | exec.Command("osascript", "-e", fmt.Sprintf(`tell application "LaunchBar"
31 | perform action "Paste in Frontmost Application" with string "%s"
32 | end tell`, word)).Start()
33 | } else {
34 | exec.Command("open", "dict://"+url.QueryEscape(word)).Start()
35 | }
36 | },
37 | }
38 |
39 | func init() {
40 | pb = NewAction("Live Dictionary", ConfigValues{
41 | "actionDefaultScript": "dict",
42 | "debug": false,
43 | "limit": 10,
44 | "autoupdate": true,
45 | })
46 | pb.Config.Set("indev", InDev != "")
47 | }
48 |
49 | func main() {
50 | pb.Init(funcs)
51 |
52 | width := float64(300)
53 | LBPlistPath := os.ExpandEnv("$HOME/Library/Preferences/at.obdev.LaunchBar.plist")
54 | if fd, err := os.Open(LBPlistPath); err == nil {
55 | defer fd.Close()
56 | var pl map[string]interface{}
57 | decoder := plist.NewDecoder(fd)
58 | if err := decoder.Decode(&pl); err == nil && pl["LaunchBarWindowWidth"] != nil {
59 | width = float64(reflect.ValueOf(pl["LaunchBarWindowWidth"]).Float())
60 | } else if err != nil {
61 | pb.Logger.Println(err)
62 | }
63 | } else {
64 | pb.Logger.Println(err)
65 | }
66 |
67 | if InDev != "" {
68 | pb.Logger.Printf("in:\n%s\n", pb.Input.Raw())
69 | }
70 |
71 | in := pb.Input
72 |
73 | var i *Item
74 | v := pb.NewView("main")
75 | q := strings.TrimSpace(in.String())
76 | definitions := lookup(q, int(pb.Config.GetInt("limit")))
77 |
78 | if q != "" && len(definitions) == 0 {
79 | i = v.NewItem(in.String())
80 | i.SetIcon("com.apple.Dictionary")
81 | i.Run("openDictionary", q)
82 | }
83 | for _, row := range definitions {
84 | word := row[0]
85 | def := row[1]
86 | pos := strings.Index(def, "▶")
87 | if pos != -1 {
88 | def = def[pos+len("▶"):]
89 | }
90 |
91 | fields := strings.Fields(def)
92 | maxChars := int(width / 7)
93 | totalLen := 0
94 | parts := make([]string, 0, len(fields))
95 | for _, field := range fields {
96 | l := len([]rune(field))
97 | if totalLen+l+len("…") < maxChars {
98 | parts = append(parts, field)
99 | totalLen += l + 1
100 | } else {
101 | parts = append(parts, "…")
102 | break
103 | }
104 | }
105 | def = strings.Join(parts, " ")
106 |
107 | i = v.NewItem(word)
108 | i.SetSubtitle(def)
109 | i.SetIcon("DictionaryOn")
110 | i.Run("openDictionary", word)
111 | }
112 | if len(definitions) > 0 {
113 | if definitions[0][0] != q {
114 | i = v.NewItem(q)
115 | i.SetIcon("DictionaryOff")
116 | i.Run("openDictionary", q)
117 | i.SetSubtitle(q)
118 | } else {
119 | v.Items[0].SetIcon("com.apple.Dictionary")
120 | }
121 |
122 | // i = v.NewItem("⌃+Enter to open Dictionary.app")
123 | // i.SetIcon("LinkArrowTemplate")
124 | // i.SetAction("")
125 |
126 | // i = v.NewItem("⇧+Enter to paste in frontmost application")
127 | // i.SetIcon("at.obdev.LaunchBar:CopyActionTemplate")
128 | // i.SetAction("")
129 | }
130 |
131 | out := pb.Run()
132 |
133 | if false && InDev != "" {
134 | nice := out
135 | js, err := sjson.NewJson([]byte(out))
136 | if err == nil {
137 | b, err := js.EncodePretty()
138 | if err == nil {
139 | nice = string(b)
140 | }
141 | }
142 | pb.Logger.Println("out:", string(nice))
143 | }
144 |
145 | fmt.Println(out)
146 | }
147 |
--------------------------------------------------------------------------------
/vendor/manifest:
--------------------------------------------------------------------------------
1 | {
2 | "version": 0,
3 | "dependencies": [
4 | {
5 | "importpath": "github.com/DHowett/go-plist",
6 | "repository": "https://github.com/DHowett/go-plist",
7 | "revision": "c61954340689b1debd57cad98f0b5efe8cf75d4a",
8 | "branch": "HEAD"
9 | },
10 | {
11 | "importpath": "github.com/bitly/go-simplejson",
12 | "repository": "https://github.com/bitly/go-simplejson",
13 | "revision": "3378bdcb5cebedcbf8b5750edee28010f128fe24",
14 | "branch": "HEAD"
15 | },
16 | {
17 | "importpath": "github.com/codegangsta/inject",
18 | "repository": "https://github.com/codegangsta/inject",
19 | "revision": "37512bbe41b4cc579cdd706742efc7bf34f94b06",
20 | "branch": "HEAD"
21 | },
22 | {
23 | "importpath": "github.com/nbjahan/go-launchbar",
24 | "repository": "https://github.com/nbjahan/go-launchbar",
25 | "revision": "671da67faca26391b80ae91e46f15434931bf508",
26 | "branch": "HEAD"
27 | }
28 | ]
29 | }
--------------------------------------------------------------------------------
/vendor/src/github.com/DHowett/go-plist/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013, Dustin L. Howett. All rights reserved.
2 |
3 | Redistribution and use in source and binary forms, with or without
4 | modification, are permitted provided that the following conditions are met:
5 |
6 | 1. Redistributions of source code must retain the above copyright notice, this
7 | list of conditions and the following disclaimer.
8 | 2. Redistributions in binary form must reproduce the above copyright notice,
9 | this list of conditions and the following disclaimer in the documentation
10 | and/or other materials provided with the distribution.
11 |
12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
13 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
16 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
19 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22 |
23 | The views and conclusions contained in the software and documentation are those
24 | of the authors and should not be interpreted as representing official policies,
25 | either expressed or implied, of the FreeBSD Project.
26 |
27 | --------------------------------------------------------------------------------
28 | Parts of this package were made available under the license covering
29 | the Go language and all attended core libraries. That license follows.
30 | --------------------------------------------------------------------------------
31 |
32 | Copyright (c) 2012 The Go Authors. All rights reserved.
33 |
34 | Redistribution and use in source and binary forms, with or without
35 | modification, are permitted provided that the following conditions are
36 | met:
37 |
38 | * Redistributions of source code must retain the above copyright
39 | notice, this list of conditions and the following disclaimer.
40 | * Redistributions in binary form must reproduce the above
41 | copyright notice, this list of conditions and the following disclaimer
42 | in the documentation and/or other materials provided with the
43 | distribution.
44 | * Neither the name of Google Inc. nor the names of its
45 | contributors may be used to endorse or promote products derived from
46 | this software without specific prior written permission.
47 |
48 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
49 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
50 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
51 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
52 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
53 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
54 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
55 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
56 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
57 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
58 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
59 |
--------------------------------------------------------------------------------
/vendor/src/github.com/DHowett/go-plist/README.md:
--------------------------------------------------------------------------------
1 | # plist - A pure Go property list transcoder
2 | ## INSTALL
3 | $ go get howett.net/plist
4 |
5 | ## FEATURES
6 | * Supports encoding/decoding property lists (Apple XML, Apple Binary, OpenStep and GNUStep) from/to arbitrary Go types
7 |
8 | ## USE
9 | ```go
10 | package main
11 | import (
12 | "howett.net/plist"
13 | "os"
14 | )
15 | func main() {
16 | encoder := plist.NewEncoder(os.Stdout)
17 | encoder.Encode(map[string]string{"hello": "world"})
18 | }
19 | ```
20 |
--------------------------------------------------------------------------------
/vendor/src/github.com/DHowett/go-plist/bplist.go:
--------------------------------------------------------------------------------
1 | package plist
2 |
3 | import (
4 | "bytes"
5 | "encoding/binary"
6 | "errors"
7 | "fmt"
8 | "hash/crc32"
9 | "io"
10 | "math"
11 | "runtime"
12 | "time"
13 | "unicode/utf16"
14 | )
15 |
16 | type bplistTrailer struct {
17 | Unused [5]uint8
18 | SortVersion uint8
19 | OffsetIntSize uint8
20 | ObjectRefSize uint8
21 | NumObjects uint64
22 | TopObject uint64
23 | OffsetTableOffset uint64
24 | }
25 |
26 | const (
27 | bpTagNull uint8 = 0x00
28 | bpTagBoolFalse = 0x08
29 | bpTagBoolTrue = 0x09
30 | bpTagInteger = 0x10
31 | bpTagReal = 0x20
32 | bpTagDate = 0x30
33 | bpTagData = 0x40
34 | bpTagASCIIString = 0x50
35 | bpTagUTF16String = 0x60
36 | bpTagUID = 0x80
37 | bpTagArray = 0xA0
38 | bpTagDictionary = 0xD0
39 | )
40 |
41 | type bplistGenerator struct {
42 | writer *countedWriter
43 | uniqmap map[interface{}]uint64
44 | objmap map[*plistValue]uint64
45 | objtable []*plistValue
46 | nobjects uint64
47 | trailer bplistTrailer
48 | }
49 |
50 | func (p *bplistGenerator) flattenPlistValue(pval *plistValue) {
51 | switch pval.kind {
52 | case String, Integer, Real:
53 | if _, ok := p.uniqmap[pval.value]; ok {
54 | return
55 | }
56 | p.uniqmap[pval.value] = p.nobjects
57 | case Date:
58 | k := pval.value.(time.Time).UnixNano()
59 | if _, ok := p.uniqmap[k]; ok {
60 | return
61 | }
62 | p.uniqmap[k] = p.nobjects
63 | case Data:
64 | // Data are uniqued by their checksums.
65 | // The wonderful difference between uint64 (which we use for numbers)
66 | // and uint32 makes this possible.
67 | // Todo: Look at calculating this only once and storing it somewhere;
68 | // crc32 is fairly quick, however.
69 | uniqkey := crc32.ChecksumIEEE(pval.value.([]byte))
70 | if _, ok := p.uniqmap[uniqkey]; ok {
71 | return
72 | }
73 | p.uniqmap[uniqkey] = p.nobjects
74 | }
75 |
76 | p.objtable = append(p.objtable, pval)
77 | p.objmap[pval] = p.nobjects
78 | p.nobjects++
79 |
80 | switch pval.kind {
81 | case Dictionary:
82 | dict := pval.value.(*dictionary)
83 | dict.populateArrays()
84 | for _, k := range dict.keys {
85 | p.flattenPlistValue(&plistValue{String, k})
86 | }
87 | for _, v := range dict.values {
88 | p.flattenPlistValue(v)
89 | }
90 | case Array:
91 | subvalues := pval.value.([]*plistValue)
92 | for _, v := range subvalues {
93 | p.flattenPlistValue(v)
94 | }
95 | }
96 | }
97 |
98 | func (p *bplistGenerator) indexForPlistValue(pval *plistValue) (uint64, bool) {
99 | var v uint64
100 | var ok bool
101 | switch pval.kind {
102 | case String, Integer, Real:
103 | v, ok = p.uniqmap[pval.value]
104 | case Date:
105 | v, ok = p.uniqmap[pval.value.(time.Time).UnixNano()]
106 | case Data:
107 | v, ok = p.uniqmap[crc32.ChecksumIEEE(pval.value.([]byte))]
108 | default:
109 | v, ok = p.objmap[pval]
110 | }
111 | return v, ok
112 | }
113 |
114 | func (p *bplistGenerator) generateDocument(rootpval *plistValue) {
115 | p.objtable = make([]*plistValue, 0, 15)
116 | p.uniqmap = make(map[interface{}]uint64)
117 | p.objmap = make(map[*plistValue]uint64)
118 | p.flattenPlistValue(rootpval)
119 |
120 | p.trailer.NumObjects = uint64(len(p.objtable))
121 | p.trailer.ObjectRefSize = uint8(minimumSizeForInt(p.trailer.NumObjects))
122 |
123 | p.writer.Write([]byte("bplist00"))
124 |
125 | offtable := make([]uint64, p.trailer.NumObjects)
126 | for i, pval := range p.objtable {
127 | offtable[i] = uint64(p.writer.BytesWritten())
128 | p.writePlistValue(pval)
129 | }
130 |
131 | p.trailer.OffsetIntSize = uint8(minimumSizeForInt(uint64(p.writer.BytesWritten())))
132 | p.trailer.TopObject = p.objmap[rootpval]
133 | p.trailer.OffsetTableOffset = uint64(p.writer.BytesWritten())
134 |
135 | for _, offset := range offtable {
136 | p.writeSizedInt(offset, int(p.trailer.OffsetIntSize))
137 | }
138 |
139 | binary.Write(p.writer, binary.BigEndian, p.trailer)
140 | }
141 |
142 | func (p *bplistGenerator) writePlistValue(pval *plistValue) {
143 | if pval == nil {
144 | return
145 | }
146 |
147 | switch pval.kind {
148 | case Dictionary:
149 | p.writeDictionaryTag(pval.value.(*dictionary))
150 | case Array:
151 | p.writeArrayTag(pval.value.([]*plistValue))
152 | case String:
153 | p.writeStringTag(pval.value.(string))
154 | case Integer:
155 | p.writeIntTag(pval.value.(signedInt).value)
156 | case Real:
157 | p.writeRealTag(pval.value.(sizedFloat).value, pval.value.(sizedFloat).bits)
158 | case Boolean:
159 | p.writeBoolTag(pval.value.(bool))
160 | case Data:
161 | p.writeDataTag(pval.value.([]byte))
162 | case Date:
163 | p.writeDateTag(pval.value.(time.Time))
164 | }
165 | }
166 |
167 | func minimumSizeForInt(n uint64) int {
168 | switch {
169 | case n <= uint64(0xff):
170 | return 1
171 | case n <= uint64(0xffff):
172 | return 2
173 | case n <= uint64(0xffffffff):
174 | return 4
175 | default:
176 | return 8
177 | }
178 | panic(errors.New("illegal integer size"))
179 | }
180 |
181 | func (p *bplistGenerator) writeSizedInt(n uint64, nbytes int) {
182 | var val interface{}
183 | switch nbytes {
184 | case 1:
185 | val = uint8(n)
186 | case 2:
187 | val = uint16(n)
188 | case 4:
189 | val = uint32(n)
190 | case 8:
191 | val = n
192 | default:
193 | panic(errors.New("illegal integer size"))
194 | }
195 | binary.Write(p.writer, binary.BigEndian, val)
196 | }
197 |
198 | func (p *bplistGenerator) writeBoolTag(v bool) {
199 | tag := uint8(bpTagBoolFalse)
200 | if v {
201 | tag = bpTagBoolTrue
202 | }
203 | binary.Write(p.writer, binary.BigEndian, tag)
204 | }
205 |
206 | func (p *bplistGenerator) writeIntTag(n uint64) {
207 | var tag uint8
208 | var val interface{}
209 | switch {
210 | case n <= uint64(0xff):
211 | val = uint8(n)
212 | tag = bpTagInteger | 0x0
213 | case n <= uint64(0xffff):
214 | val = uint16(n)
215 | tag = bpTagInteger | 0x1
216 | case n <= uint64(0xffffffff):
217 | val = uint32(n)
218 | tag = bpTagInteger | 0x2
219 | default:
220 | val = n
221 | tag = bpTagInteger | 0x3
222 | }
223 |
224 | binary.Write(p.writer, binary.BigEndian, tag)
225 | binary.Write(p.writer, binary.BigEndian, val)
226 | }
227 |
228 | func (p *bplistGenerator) writeRealTag(n float64, bits int) {
229 | var tag uint8 = bpTagReal | 0x3
230 | var val interface{} = n
231 | if bits == 32 {
232 | val = float32(n)
233 | tag = bpTagReal | 0x2
234 | }
235 |
236 | binary.Write(p.writer, binary.BigEndian, tag)
237 | binary.Write(p.writer, binary.BigEndian, val)
238 | }
239 |
240 | func (p *bplistGenerator) writeDateTag(t time.Time) {
241 | tag := uint8(bpTagDate) | 0x3
242 | val := float64(t.In(time.UTC).UnixNano()) / float64(time.Second)
243 | val -= 978307200 // Adjust to Apple Epoch
244 |
245 | binary.Write(p.writer, binary.BigEndian, tag)
246 | binary.Write(p.writer, binary.BigEndian, val)
247 | }
248 |
249 | func (p *bplistGenerator) writeCountedTag(tag uint8, count uint64) {
250 | marker := tag
251 | if count >= 0xF {
252 | marker |= 0xF
253 | } else {
254 | marker |= uint8(count)
255 | }
256 |
257 | binary.Write(p.writer, binary.BigEndian, marker)
258 |
259 | if count >= 0xF {
260 | p.writeIntTag(count)
261 | }
262 | }
263 |
264 | func (p *bplistGenerator) writeDataTag(data []byte) {
265 | p.writeCountedTag(bpTagData, uint64(len(data)))
266 | binary.Write(p.writer, binary.BigEndian, data)
267 | }
268 |
269 | func (p *bplistGenerator) writeStringTag(str string) {
270 | for _, r := range str {
271 | if r > 0xFF {
272 | utf16Runes := utf16.Encode([]rune(str))
273 | p.writeCountedTag(bpTagUTF16String, uint64(len(utf16Runes)))
274 | binary.Write(p.writer, binary.BigEndian, utf16Runes)
275 | return
276 | }
277 | }
278 |
279 | p.writeCountedTag(bpTagASCIIString, uint64(len(str)))
280 | binary.Write(p.writer, binary.BigEndian, []byte(str))
281 | }
282 |
283 | func (p *bplistGenerator) writeDictionaryTag(dict *dictionary) {
284 | p.writeCountedTag(bpTagDictionary, uint64(dict.count))
285 | vals := make([]uint64, dict.count*2)
286 | cnt := dict.count
287 | for i, k := range dict.keys {
288 | keyIdx, ok := p.uniqmap[k]
289 | if !ok {
290 | panic(errors.New("failed to find key " + k + " in object map during serialization"))
291 | }
292 | vals[i] = keyIdx
293 | }
294 | for i, v := range dict.values {
295 | objIdx, ok := p.indexForPlistValue(v)
296 | if !ok {
297 | panic(errors.New("failed to find value in object map during serialization"))
298 | }
299 | vals[i+cnt] = objIdx
300 | }
301 |
302 | for _, v := range vals {
303 | p.writeSizedInt(v, int(p.trailer.ObjectRefSize))
304 | }
305 | }
306 |
307 | func (p *bplistGenerator) writeArrayTag(arr []*plistValue) {
308 | p.writeCountedTag(bpTagArray, uint64(len(arr)))
309 | for _, v := range arr {
310 | objIdx, ok := p.indexForPlistValue(v)
311 | if !ok {
312 | panic(errors.New("failed to find value in object map during serialization"))
313 | }
314 |
315 | p.writeSizedInt(objIdx, int(p.trailer.ObjectRefSize))
316 | }
317 | }
318 |
319 | func (p *bplistGenerator) Indent(i string) {
320 | // There's nothing to indent.
321 | }
322 |
323 | func newBplistGenerator(w io.Writer) *bplistGenerator {
324 | return &bplistGenerator{
325 | writer: &countedWriter{Writer: mustWriter{w}},
326 | }
327 | }
328 |
329 | type bplistParser struct {
330 | reader io.ReadSeeker
331 | version int
332 | buf []byte
333 | objrefs map[uint64]*plistValue
334 | offtable []uint64
335 | trailer bplistTrailer
336 | }
337 |
338 | func (p *bplistParser) parseDocument() (pval *plistValue, parseError error) {
339 | defer func() {
340 | if r := recover(); r != nil {
341 | if _, ok := r.(runtime.Error); ok {
342 | panic(r)
343 | }
344 | if _, ok := r.(invalidPlistError); ok {
345 | parseError = r.(error)
346 | } else {
347 | // Wrap all non-invalid-plist errors.
348 | parseError = plistParseError{"binary", r.(error)}
349 | }
350 | }
351 | }()
352 |
353 | magic := make([]byte, 6)
354 | ver := make([]byte, 2)
355 | p.reader.Seek(0, 0)
356 | p.reader.Read(magic)
357 | if !bytes.Equal(magic, []byte("bplist")) {
358 | panic(invalidPlistError{"binary", errors.New("mismatched magic")})
359 | }
360 |
361 | _, err := p.reader.Read(ver)
362 | if err != nil {
363 | panic(err)
364 | }
365 |
366 | p.version = int(mustParseInt(string(ver), 10, 0))
367 |
368 | if p.version > 1 {
369 | panic(fmt.Errorf("unexpected version %d", p.version))
370 | }
371 |
372 | p.objrefs = make(map[uint64]*plistValue)
373 | _, err = p.reader.Seek(-32, 2)
374 | if err != nil && err != io.EOF {
375 | panic(err)
376 | }
377 |
378 | err = binary.Read(p.reader, binary.BigEndian, &p.trailer)
379 | if err != nil && err != io.EOF {
380 | panic(err)
381 | }
382 |
383 | p.offtable = make([]uint64, p.trailer.NumObjects)
384 |
385 | // SEEK_SET
386 | _, err = p.reader.Seek(int64(p.trailer.OffsetTableOffset), 0)
387 | if err != nil && err != io.EOF {
388 | panic(err)
389 | }
390 |
391 | for i := uint64(0); i < p.trailer.NumObjects; i++ {
392 | off := p.readSizedInt(int(p.trailer.OffsetIntSize))
393 | p.offtable[i] = off
394 | }
395 |
396 | for _, off := range p.offtable {
397 | p.valueAtOffset(off)
398 | }
399 |
400 | pval = p.valueAtOffset(p.offtable[p.trailer.TopObject])
401 | return
402 | }
403 |
404 | func (p *bplistParser) readSizedInt(nbytes int) uint64 {
405 | switch nbytes {
406 | case 1:
407 | var val uint8
408 | binary.Read(p.reader, binary.BigEndian, &val)
409 | return uint64(val)
410 | case 2:
411 | var val uint16
412 | binary.Read(p.reader, binary.BigEndian, &val)
413 | return uint64(val)
414 | case 4:
415 | var val uint32
416 | binary.Read(p.reader, binary.BigEndian, &val)
417 | return uint64(val)
418 | case 8:
419 | var val uint64
420 | binary.Read(p.reader, binary.BigEndian, &val)
421 | return uint64(val)
422 | case 16:
423 | var high, low uint64
424 | binary.Read(p.reader, binary.BigEndian, &high)
425 | binary.Read(p.reader, binary.BigEndian, &low)
426 | // TODO: int128 support (!)
427 | return uint64(low)
428 | }
429 | panic(errors.New("illegal integer size"))
430 | }
431 |
432 | func (p *bplistParser) countForTag(tag uint8) uint64 {
433 | cnt := uint64(tag & 0x0F)
434 | if cnt == 0xF {
435 | var intTag uint8
436 | binary.Read(p.reader, binary.BigEndian, &intTag)
437 | cnt = p.readSizedInt(1 << (intTag & 0xF))
438 | }
439 | return cnt
440 | }
441 |
442 | func (p *bplistParser) valueAtOffset(off uint64) *plistValue {
443 | if pval, ok := p.objrefs[off]; ok {
444 | return pval
445 | }
446 | pval := p.parseTagAtOffset(int64(off))
447 | p.objrefs[off] = pval
448 | return pval
449 | }
450 |
451 | func (p *bplistParser) parseTagAtOffset(off int64) *plistValue {
452 | var tag uint8
453 | p.reader.Seek(off, 0)
454 | binary.Read(p.reader, binary.BigEndian, &tag)
455 |
456 | switch tag & 0xF0 {
457 | case bpTagNull:
458 | switch tag & 0x0F {
459 | case bpTagBoolTrue, bpTagBoolFalse:
460 | return &plistValue{Boolean, tag == bpTagBoolTrue}
461 | }
462 | return nil
463 | case bpTagInteger:
464 | val := p.readSizedInt(1 << (tag & 0xF))
465 | return &plistValue{Integer, signedInt{val, false}}
466 | case bpTagReal:
467 | nbytes := 1 << (tag & 0x0F)
468 | switch nbytes {
469 | case 4:
470 | var val float32
471 | binary.Read(p.reader, binary.BigEndian, &val)
472 | return &plistValue{Real, sizedFloat{float64(val), 32}}
473 | case 8:
474 | var val float64
475 | binary.Read(p.reader, binary.BigEndian, &val)
476 | return &plistValue{Real, sizedFloat{float64(val), 64}}
477 | }
478 | panic(errors.New("illegal float size"))
479 | case bpTagDate:
480 | var val float64
481 | binary.Read(p.reader, binary.BigEndian, &val)
482 |
483 | // Apple Epoch is 20110101000000Z
484 | // Adjust for UNIX Time
485 | val += 978307200
486 |
487 | sec, fsec := math.Modf(val)
488 | time := time.Unix(int64(sec), int64(fsec*float64(time.Second))).In(time.UTC)
489 | return &plistValue{Date, time}
490 | case bpTagData:
491 | cnt := p.countForTag(tag)
492 |
493 | bytes := make([]byte, cnt)
494 | binary.Read(p.reader, binary.BigEndian, bytes)
495 | return &plistValue{Data, bytes}
496 | case bpTagASCIIString, bpTagUTF16String:
497 | cnt := p.countForTag(tag)
498 |
499 | if tag&0xF0 == bpTagASCIIString {
500 | bytes := make([]byte, cnt)
501 | binary.Read(p.reader, binary.BigEndian, bytes)
502 | return &plistValue{String, string(bytes)}
503 | } else {
504 | bytes := make([]uint16, cnt)
505 | binary.Read(p.reader, binary.BigEndian, bytes)
506 | runes := utf16.Decode(bytes)
507 | return &plistValue{String, string(runes)}
508 | }
509 | case bpTagUID: // Somehow different than int: low half is nbytes - 1 instead of log2(nbytes)
510 | val := p.readSizedInt(int(tag&0xF) + 1)
511 | return &plistValue{Integer, signedInt{val, false}}
512 | case bpTagDictionary:
513 | cnt := p.countForTag(tag)
514 |
515 | subvalues := make(map[string]*plistValue)
516 | indices := make([]uint64, cnt*2)
517 | for i := uint64(0); i < cnt*2; i++ {
518 | idx := p.readSizedInt(int(p.trailer.ObjectRefSize))
519 | indices[i] = idx
520 | }
521 | for i := uint64(0); i < cnt; i++ {
522 | kval := p.valueAtOffset(p.offtable[indices[i]])
523 | subvalues[kval.value.(string)] = p.valueAtOffset(p.offtable[indices[i+cnt]])
524 | }
525 |
526 | return &plistValue{Dictionary, &dictionary{m: subvalues}}
527 | case bpTagArray:
528 | cnt := p.countForTag(tag)
529 |
530 | arr := make([]*plistValue, cnt)
531 | indices := make([]uint64, cnt)
532 | for i := uint64(0); i < cnt; i++ {
533 | indices[i] = p.readSizedInt(int(p.trailer.ObjectRefSize))
534 | }
535 | for i := uint64(0); i < cnt; i++ {
536 | arr[i] = p.valueAtOffset(p.offtable[indices[i]])
537 | }
538 |
539 | return &plistValue{Array, arr}
540 | }
541 | panic(fmt.Errorf("unexpected atom 0x%2.02x at offset %d", tag, off))
542 | }
543 |
544 | func newBplistParser(r io.ReadSeeker) *bplistParser {
545 | return &bplistParser{reader: r}
546 | }
547 |
--------------------------------------------------------------------------------
/vendor/src/github.com/DHowett/go-plist/bplist_test.go:
--------------------------------------------------------------------------------
1 | package plist
2 |
3 | import (
4 | "bytes"
5 | "io/ioutil"
6 | "testing"
7 | )
8 |
9 | func BenchmarkBplistGenerate(b *testing.B) {
10 | for i := 0; i < b.N; i++ {
11 | d := newBplistGenerator(ioutil.Discard)
12 | d.generateDocument(plistValueTree)
13 | }
14 | }
15 |
16 | func BenchmarkBplistParse(b *testing.B) {
17 | buf := bytes.NewReader(plistValueTreeAsBplist)
18 | b.ResetTimer()
19 | for i := 0; i < b.N; i++ {
20 | b.StartTimer()
21 | d := newBplistParser(buf)
22 | d.parseDocument()
23 | b.StopTimer()
24 | buf.Seek(0, 0)
25 | }
26 | }
27 |
28 | func TestBplistInt128(t *testing.T) {
29 | bplist := []byte{0x62, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x30, 0x30, 0x14, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19}
30 | expected := uint64(0x090a0b0c0d0e0f10)
31 | buf := bytes.NewReader(bplist)
32 | d := newBplistParser(buf)
33 | pval, _ := d.parseDocument()
34 | if pval.kind != Integer || pval.value.(signedInt).value != expected {
35 | t.Error("Expected", expected, "received", pval.value)
36 | }
37 | }
38 |
39 | func TestVariousIllegalBplists(t *testing.T) {
40 | bplists := [][]byte{
41 | []byte{0x62, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x30, 0x30, 0x13},
42 | []byte{0x62, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x30, 0x30, 0x15, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19},
43 | []byte{0x62, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x30, 0x30, 0x24, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19},
44 | []byte{0x62, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x30, 0x30, 0xFF, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19},
45 | []byte{0x62, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x40, 0x41},
46 | []byte{0x62, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x30, 0x32},
47 | []byte{0x62, 0x71, 0x6c, 0x69, 0x73, 0x74, 0x30, 0x30},
48 | }
49 |
50 | for _, bplist := range bplists {
51 | // We don't want the fallback behaviour for our bad file tests.
52 | buf := bytes.NewReader(bplist)
53 | d := newBplistParser(buf)
54 | _, err := d.parseDocument()
55 | t.Logf("Error: %v", err)
56 | if err == nil {
57 | t.Error("Expected error, received nothing.")
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/vendor/src/github.com/DHowett/go-plist/decode.go:
--------------------------------------------------------------------------------
1 | package plist
2 |
3 | import (
4 | "bytes"
5 | "io"
6 | "reflect"
7 | "runtime"
8 | )
9 |
10 | type parser interface {
11 | parseDocument() (*plistValue, error)
12 | }
13 |
14 | // A Decoder reads a property list from an input stream.
15 | type Decoder struct {
16 | // the format of the most-recently-decoded property list
17 | Format int
18 |
19 | reader io.ReadSeeker
20 | lax bool
21 | }
22 |
23 | // Decode works like Unmarshal, except it reads the decoder stream to find property list elements.
24 | //
25 | // After Decoding, the Decoder's Format field will be set to one of the plist format constants.
26 | func (p *Decoder) Decode(v interface{}) (err error) {
27 | defer func() {
28 | if r := recover(); r != nil {
29 | if _, ok := r.(runtime.Error); ok {
30 | panic(r)
31 | }
32 | err = r.(error)
33 | }
34 | }()
35 |
36 | header := make([]byte, 6)
37 | p.reader.Read(header)
38 | p.reader.Seek(0, 0)
39 |
40 | var parser parser
41 | var pval *plistValue
42 | if bytes.Equal(header, []byte("bplist")) {
43 | parser = newBplistParser(p.reader)
44 | pval, err = parser.parseDocument()
45 | if err != nil {
46 | // Had a bplist header, but still got an error: we have to die here.
47 | return err
48 | }
49 | p.Format = BinaryFormat
50 | } else {
51 | parser = newXMLPlistParser(p.reader)
52 | pval, err = parser.parseDocument()
53 | if _, ok := err.(invalidPlistError); ok {
54 | // Rewind: the XML parser might have exhausted the file.
55 | p.reader.Seek(0, 0)
56 | // We don't use parser here because we want the textPlistParser type
57 | tp := newTextPlistParser(p.reader)
58 | pval, err = tp.parseDocument()
59 | if err != nil {
60 | return err
61 | }
62 | p.Format = tp.format
63 | if p.Format == OpenStepFormat {
64 | // OpenStep property lists can only store strings,
65 | // so we have to turn on lax mode here for the unmarshal step later.
66 | p.lax = true
67 | }
68 | } else {
69 | if err != nil {
70 | return err
71 | }
72 | p.Format = XMLFormat
73 | }
74 | }
75 |
76 | p.unmarshal(pval, reflect.ValueOf(v))
77 | return
78 | }
79 |
80 | // NewDecoder returns a Decoder that reads property list elements from a stream reader, r.
81 | // NewDecoder requires a Seekable stream for the purposes of file type detection.
82 | func NewDecoder(r io.ReadSeeker) *Decoder {
83 | return &Decoder{Format: InvalidFormat, reader: r, lax: false}
84 | }
85 |
86 | // Unmarshal parses a property list document and stores the result in the value pointed to by v.
87 | //
88 | // Unmarshal uses the inverse of the type encodings that Marshal uses, allocating heap-borne types as necessary.
89 | //
90 | // When given a nil pointer, Unmarshal allocates a new value for it to point to.
91 | //
92 | // To decode property list values into an interface value, Unmarshal decodes the property list into the concrete value contained
93 | // in the interface value. If the interface value is nil, Unmarshal stores one of the following in the interface value:
94 | //
95 | // string, bool, uint64, float64
96 | // []byte, for plist data
97 | // []interface{}, for plist arrays
98 | // map[string]interface{}, for plist dictionaries
99 | //
100 | // If a property list value is not appropriate for a given value type, Unmarshal aborts immediately and returns an error.
101 | //
102 | // As Go does not support 128-bit types, and we don't want to pretend we're giving the user integer types (as opposed to
103 | // secretly passing them structs), Unmarshal will drop the high 64 bits of any 128-bit integers encoded in binary property lists.
104 | // (This is important because CoreFoundation serializes some large 64-bit values as 128-bit values with an empty high half.)
105 | //
106 | // When Unmarshal encounters an OpenStep property list, it will enter a relaxed parsing mode: OpenStep property lists can only store
107 | // plain old data as strings, so we will attempt to recover integer, floating-point, boolean and date values wherever they are necessary.
108 | // (for example, if Unmarshal attempts to unmarshal an OpenStep property list into a time.Time, it will try to parse the string it
109 | // receives as a time.)
110 | //
111 | // Unmarshal returns the detected property list format and an error, if any.
112 | func Unmarshal(data []byte, v interface{}) (format int, err error) {
113 | r := bytes.NewReader(data)
114 | dec := NewDecoder(r)
115 | err = dec.Decode(v)
116 | format = dec.Format
117 | return
118 | }
119 |
--------------------------------------------------------------------------------
/vendor/src/github.com/DHowett/go-plist/decode_test.go:
--------------------------------------------------------------------------------
1 | package plist
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 | "reflect"
7 | "testing"
8 | )
9 |
10 | func BenchmarkXMLDecode(b *testing.B) {
11 | for i := 0; i < b.N; i++ {
12 | b.StopTimer()
13 | var bval interface{}
14 | buf := bytes.NewReader([]byte(plistValueTreeAsXML))
15 | b.StartTimer()
16 | decoder := NewDecoder(buf)
17 | decoder.Decode(bval)
18 | b.StopTimer()
19 | }
20 | }
21 |
22 | func BenchmarkBplistDecode(b *testing.B) {
23 | for i := 0; i < b.N; i++ {
24 | b.StopTimer()
25 | var bval interface{}
26 | buf := bytes.NewReader(plistValueTreeAsBplist)
27 | b.StartTimer()
28 | decoder := NewDecoder(buf)
29 | decoder.Decode(bval)
30 | b.StopTimer()
31 | }
32 | }
33 |
34 | func TestLaxDecode(t *testing.T) {
35 | var laxTestDataStringsOnlyAsXML = `{B=1;D="2013-11-27 00:34:00 +0000";I64=1;F64="3.0";U64=2;}`
36 | d := LaxTestData{}
37 | buf := bytes.NewReader([]byte(laxTestDataStringsOnlyAsXML))
38 | decoder := NewDecoder(buf)
39 | decoder.lax = true
40 | err := decoder.Decode(&d)
41 | if err != nil {
42 | t.Error(err.Error())
43 | }
44 |
45 | if d != laxTestData {
46 | t.Logf("Expected: %#v", laxTestData)
47 | t.Logf("Received: %#v", d)
48 | t.Fail()
49 | }
50 | }
51 |
52 | func TestIllegalLaxDecode(t *testing.T) {
53 | i := int64(0)
54 | u := uint64(0)
55 | f := float64(0)
56 | b := false
57 | plists := []struct {
58 | pl string
59 | d interface{}
60 | }{
61 | {"abc", &i},
62 | {"abc", &u},
63 | {"def", &f},
64 | {"ghi", &b},
65 | {"jkl", []byte{0x00}},
66 | }
67 |
68 | for _, plist := range plists {
69 | buf := bytes.NewReader([]byte(plist.pl))
70 | decoder := NewDecoder(buf)
71 | decoder.lax = true
72 | err := decoder.Decode(plist.d)
73 | t.Logf("Error: %v", err)
74 | if err == nil {
75 | t.Error("Expected error, received nothing.")
76 | }
77 | }
78 | }
79 |
80 | func TestIllegalDecode(t *testing.T) {
81 | i := int64(0)
82 | b := false
83 | plists := []struct {
84 | pl string
85 | d interface{}
86 | }{
87 | {"abc", &i},
88 | {"ABC=", &i},
89 | {"34.1", &i},
90 | {"def", &i},
91 | {"2010-01-01T00:00:00Z", &i},
92 | {"0", &b},
93 | {"0", &b},
94 | {"a0", &b},
95 | {"", &[1]int{1}},
96 | }
97 |
98 | for _, plist := range plists {
99 | buf := bytes.NewReader([]byte(plist.pl))
100 | decoder := NewDecoder(buf)
101 | err := decoder.Decode(plist.d)
102 | t.Logf("Error: %v", err)
103 | if err == nil {
104 | t.Error("Expected error, received nothing.")
105 | }
106 | }
107 | }
108 |
109 | func TestDecode(t *testing.T) {
110 | var failed bool
111 | for _, test := range tests {
112 | failed = false
113 |
114 | t.Logf("Testing Decode (%s)", test.Name)
115 |
116 | d := test.DecodeData
117 | if d == nil {
118 | d = test.Data
119 | }
120 |
121 | testData := reflect.ValueOf(d)
122 | if !testData.IsValid() || isEmptyInterface(testData) {
123 | continue
124 | }
125 | if testData.Kind() == reflect.Ptr || testData.Kind() == reflect.Interface {
126 | testData = testData.Elem()
127 | }
128 | d = testData.Interface()
129 |
130 | results := make(map[int]interface{})
131 | errors := make(map[int]error)
132 | for fmt, dat := range test.Expected {
133 | if test.SkipDecode[fmt] {
134 | continue
135 | }
136 | val := reflect.New(testData.Type()).Interface()
137 | _, errors[fmt] = Unmarshal(dat, val)
138 |
139 | vt := reflect.ValueOf(val)
140 | if vt.Kind() == reflect.Ptr || vt.Kind() == reflect.Interface {
141 | vt = vt.Elem()
142 | val = vt.Interface()
143 | }
144 |
145 | results[fmt] = val
146 |
147 | if !reflect.DeepEqual(d, val) {
148 | failed = true
149 | }
150 | }
151 |
152 | if results[BinaryFormat] != nil && results[XMLFormat] != nil {
153 | if !reflect.DeepEqual(results[BinaryFormat], results[XMLFormat]) {
154 | t.Log("Binary and XML decoding yielded different values.")
155 | t.Log("Binary:", results[BinaryFormat])
156 | t.Log("XML :", results[XMLFormat])
157 | failed = true
158 | }
159 | }
160 |
161 | if failed {
162 | t.Logf("Expected: %#v\n", d)
163 |
164 | for fmt, dat := range results {
165 | t.Logf("Received %s: %#v\n", FormatNames[fmt], dat)
166 | }
167 | for fmt, err := range errors {
168 | if err != nil {
169 | t.Logf("Error %s: %v\n", FormatNames[fmt], err)
170 | }
171 | }
172 | t.Log("FAILED")
173 | t.Fail()
174 | }
175 | }
176 | }
177 |
178 | func TestInterfaceDecode(t *testing.T) {
179 | var xval interface{}
180 | buf := bytes.NewReader([]byte{98, 112, 108, 105, 115, 116, 48, 48, 214, 1, 13, 17, 21, 25, 27, 2, 14, 18, 22, 26, 28, 88, 105, 110, 116, 97, 114, 114, 97, 121, 170, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 16, 1, 16, 8, 16, 16, 16, 32, 16, 64, 16, 2, 16, 9, 16, 17, 16, 33, 16, 65, 86, 102, 108, 111, 97, 116, 115, 162, 15, 16, 34, 66, 0, 0, 0, 35, 64, 80, 0, 0, 0, 0, 0, 0, 88, 98, 111, 111, 108, 101, 97, 110, 115, 162, 19, 20, 9, 8, 87, 115, 116, 114, 105, 110, 103, 115, 162, 23, 24, 92, 72, 101, 108, 108, 111, 44, 32, 65, 83, 67, 73, 73, 105, 0, 72, 0, 101, 0, 108, 0, 108, 0, 111, 0, 44, 0, 32, 78, 22, 117, 76, 84, 100, 97, 116, 97, 68, 1, 2, 3, 4, 84, 100, 97, 116, 101, 51, 65, 184, 69, 117, 120, 0, 0, 0, 8, 21, 30, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 68, 71, 76, 85, 94, 97, 98, 99, 107, 110, 123, 142, 147, 152, 157, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 166})
181 | decoder := NewDecoder(buf)
182 | err := decoder.Decode(&xval)
183 | if err != nil {
184 | t.Log("Error:", err)
185 | t.Fail()
186 | }
187 | }
188 |
189 | func TestFormatDetection(t *testing.T) {
190 | type formatTest struct {
191 | expectedFormat int
192 | data []byte
193 | }
194 | plists := []formatTest{
195 | {BinaryFormat, []byte{98, 112, 108, 105, 115, 116, 48, 48, 85, 72, 101, 108, 108, 111, 8, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14}},
196 | {XMLFormat, []byte(`<*I3>`)},
197 | {InvalidFormat, []byte(`bplist00`)}, // Looks like a binary property list, and bplist does not have fallbacks(!)
198 | {OpenStepFormat, []byte(`(1,2,3,4,5)`)},
199 | {OpenStepFormat, []byte(``)},
200 | {GNUStepFormat, []byte(`(1,2,<*I3>)`)},
201 | {OpenStepFormat, []byte{0x00}},
202 | }
203 |
204 | for _, fmttest := range plists {
205 | fmt, err := Unmarshal(fmttest.data, nil)
206 | if fmt != fmttest.expectedFormat {
207 | t.Errorf("Wanted %s, received %s.", FormatNames[fmttest.expectedFormat], FormatNames[fmt])
208 | }
209 | if err != nil {
210 | t.Logf("Error: %v", err)
211 | }
212 | }
213 | }
214 |
215 | func ExampleDecoder_Decode() {
216 | type sparseBundleHeader struct {
217 | InfoDictionaryVersion string `plist:"CFBundleInfoDictionaryVersion"`
218 | BandSize uint64 `plist:"band-size"`
219 | BackingStoreVersion int `plist:"bundle-backingstore-version"`
220 | DiskImageBundleType string `plist:"diskimage-bundle-type"`
221 | Size uint64 `plist:"size"`
222 | }
223 |
224 | buf := bytes.NewReader([]byte(`
225 |
226 |
227 |
228 | CFBundleInfoDictionaryVersion
229 | 6.0
230 | band-size
231 | 8388608
232 | bundle-backingstore-version
233 | 1
234 | diskimage-bundle-type
235 | com.apple.diskimage.sparsebundle
236 | size
237 | 4398046511104
238 |
239 | `))
240 |
241 | var data sparseBundleHeader
242 | decoder := NewDecoder(buf)
243 | err := decoder.Decode(&data)
244 | if err != nil {
245 | fmt.Println(err)
246 | }
247 | fmt.Println(data)
248 |
249 | // Output: {6.0 8388608 1 com.apple.diskimage.sparsebundle 4398046511104}
250 | }
251 |
--------------------------------------------------------------------------------
/vendor/src/github.com/DHowett/go-plist/doc.go:
--------------------------------------------------------------------------------
1 | // Package plist implements encoding and decoding of Apple's "property list" format.
2 | // Property lists come in three sorts: plain text (GNUStep and OpenStep), XML and binary.
3 | // plist supports all of them.
4 | // The mapping between property list and Go objects is described in the documentation for the Marshal and Unmarshal functions.
5 | package plist
6 |
--------------------------------------------------------------------------------
/vendor/src/github.com/DHowett/go-plist/encode.go:
--------------------------------------------------------------------------------
1 | package plist
2 |
3 | import (
4 | "bytes"
5 | "errors"
6 | "io"
7 | "reflect"
8 | "runtime"
9 | )
10 |
11 | type generator interface {
12 | generateDocument(*plistValue)
13 | Indent(string)
14 | }
15 |
16 | // An Encoder writes a property list to an output stream.
17 | type Encoder struct {
18 | writer io.Writer
19 | format int
20 |
21 | indent string
22 | }
23 |
24 | // Encode writes the property list encoding of v to the stream.
25 | func (p *Encoder) Encode(v interface{}) (err error) {
26 | defer func() {
27 | if r := recover(); r != nil {
28 | if _, ok := r.(runtime.Error); ok {
29 | panic(r)
30 | }
31 | err = r.(error)
32 | }
33 | }()
34 |
35 | pval := p.marshal(reflect.ValueOf(v))
36 | if pval == nil {
37 | panic(errors.New("plist: no root element to encode"))
38 | }
39 |
40 | var g generator
41 | switch p.format {
42 | case XMLFormat:
43 | g = newXMLPlistGenerator(p.writer)
44 | case BinaryFormat, AutomaticFormat:
45 | g = newBplistGenerator(p.writer)
46 | case OpenStepFormat, GNUStepFormat:
47 | g = newTextPlistGenerator(p.writer, p.format)
48 | }
49 | g.Indent(p.indent)
50 | g.generateDocument(pval)
51 | return
52 | }
53 |
54 | // Indent turns on pretty-printing for the XML and Text property list formats.
55 | // Each element begins on a new line and is preceded by one or more copies of indent according to its nesting depth.
56 | func (p *Encoder) Indent(indent string) {
57 | p.indent = indent
58 | }
59 |
60 | // NewEncoder returns an Encoder that writes an XML property list to w.
61 | func NewEncoder(w io.Writer) *Encoder {
62 | return NewEncoderForFormat(w, XMLFormat)
63 | }
64 |
65 | // NewEncoderForFormat returns an Encoder that writes a property list to w in the specified format.
66 | // Pass AutomaticFormat to allow the library to choose the best encoding (currently BinaryFormat).
67 | func NewEncoderForFormat(w io.Writer, format int) *Encoder {
68 | return &Encoder{
69 | writer: w,
70 | format: format,
71 | }
72 | }
73 |
74 | // NewBinaryEncoder returns an Encoder that writes a binary property list to w.
75 | func NewBinaryEncoder(w io.Writer) *Encoder {
76 | return NewEncoderForFormat(w, BinaryFormat)
77 | }
78 |
79 | // Marshal returns the property list encoding of v in the specified format.
80 | //
81 | // Pass AutomaticFormat to allow the library to choose the best encoding (currently BinaryFormat).
82 | //
83 | // Marshal traverses the value v recursively.
84 | // Any nil values encountered, other than the root, will be silently discarded as
85 | // the property list format bears no representation for nil values.
86 | //
87 | // Strings, integers of varying size, floats and booleans are encoded unchanged.
88 | // Strings bearing non-ASCII runes will be encoded differently depending upon the property list format:
89 | // UTF-8 for XML property lists and UTF-16 for binary property lists.
90 | //
91 | // Slice and Array values are encoded as property list arrays, except for
92 | // []byte values, which are encoded as data.
93 | //
94 | // Map values encode as dictionaries. The map's key type must be string; there is no provision for encoding non-string dictionary keys.
95 | //
96 | // Struct values are encoded as dictionaries, with only exported fields being serialized. Struct field encoding may be influenced with the use of tags.
97 | // The tag format is:
98 | //
99 | // `plist:"[,flags...]"`
100 | //
101 | // The following flags are supported:
102 | //
103 | // omitempty Only include the field if it is not set to the zero value for its type.
104 | //
105 | // If the key is "-", the field is ignored.
106 | //
107 | // Anonymous struct fields are encoded as if their exported fields were exposed via the outer struct.
108 | //
109 | // Pointer values encode as the value pointed to.
110 | //
111 | // Channel, complex and function values cannot be encoded. Any attempt to do so causes Marshal to return an error.
112 | func Marshal(v interface{}, format int) ([]byte, error) {
113 | return MarshalIndent(v, format, "")
114 | }
115 |
116 | // MarshalIndent works like Marshal, but each property list element
117 | // begins on a new line and is preceded by one or more copies of indent according to its nesting depth.
118 | func MarshalIndent(v interface{}, format int, indent string) ([]byte, error) {
119 | buf := &bytes.Buffer{}
120 | enc := NewEncoderForFormat(buf, format)
121 | enc.Indent(indent)
122 | if err := enc.Encode(v); err != nil {
123 | return nil, err
124 | }
125 | return buf.Bytes(), nil
126 | }
127 |
--------------------------------------------------------------------------------
/vendor/src/github.com/DHowett/go-plist/encode_test.go:
--------------------------------------------------------------------------------
1 | package plist
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 | "testing"
7 | )
8 |
9 | func BenchmarkXMLEncode(b *testing.B) {
10 | for i := 0; i < b.N; i++ {
11 | NewEncoder(&bytes.Buffer{}).Encode(plistValueTreeRawData)
12 | }
13 | }
14 |
15 | func BenchmarkBplistEncode(b *testing.B) {
16 | for i := 0; i < b.N; i++ {
17 | NewBinaryEncoder(&bytes.Buffer{}).Encode(plistValueTreeRawData)
18 | }
19 | }
20 |
21 | func BenchmarkOpenStepEncode(b *testing.B) {
22 | for i := 0; i < b.N; i++ {
23 | NewEncoderForFormat(&bytes.Buffer{}, OpenStepFormat).Encode(plistValueTreeRawData)
24 | }
25 | }
26 |
27 | func TestEncode(t *testing.T) {
28 | var failed bool
29 | for _, test := range tests {
30 | failed = false
31 | t.Logf("Testing Encode (%s)", test.Name)
32 |
33 | // A test that should render no output!
34 | errors := make(map[int]error)
35 | if test.ShouldFail && len(test.Expected) == 0 {
36 | _, err := Marshal(test.Data, XMLFormat)
37 | failed = failed || (test.ShouldFail && err == nil)
38 | }
39 |
40 | results := make(map[int][]byte)
41 | for fmt, dat := range test.Expected {
42 | results[fmt], errors[fmt] = Marshal(test.Data, fmt)
43 | failed = failed || (test.ShouldFail && errors[fmt] == nil)
44 | failed = failed || !bytes.Equal(dat, results[fmt])
45 | }
46 |
47 | if failed {
48 | t.Logf("Value: %#v", test.Data)
49 | if test.ShouldFail {
50 | t.Logf("Expected: Error")
51 | } else {
52 | printype := "%s"
53 | for fmt, dat := range test.Expected {
54 | if fmt == BinaryFormat {
55 | printype = "%+v"
56 | } else {
57 | printype = "%s"
58 | }
59 | t.Logf("Expected %s: "+printype+"\n", FormatNames[fmt], dat)
60 | }
61 | }
62 |
63 | printype := "%s"
64 | for fmt, dat := range results {
65 | if fmt == BinaryFormat {
66 | printype = "%+v"
67 | } else {
68 | printype = "%s"
69 | }
70 | t.Logf("Received %s: "+printype+"\n", FormatNames[fmt], dat)
71 | }
72 | for fmt, err := range errors {
73 | if err != nil {
74 | t.Logf("Error %s: %v\n", FormatNames[fmt], err)
75 | }
76 | }
77 | t.Log("FAILED")
78 | t.Fail()
79 | }
80 | }
81 | }
82 |
83 | func ExampleEncoder_Encode() {
84 | type sparseBundleHeader struct {
85 | InfoDictionaryVersion string `plist:"CFBundleInfoDictionaryVersion"`
86 | BandSize uint64 `plist:"band-size"`
87 | BackingStoreVersion int `plist:"bundle-backingstore-version"`
88 | DiskImageBundleType string `plist:"diskimage-bundle-type"`
89 | Size uint64 `plist:"size"`
90 | }
91 | data := &sparseBundleHeader{
92 | InfoDictionaryVersion: "6.0",
93 | BandSize: 8388608,
94 | Size: 4 * 1048576 * 1024 * 1024,
95 | DiskImageBundleType: "com.apple.diskimage.sparsebundle",
96 | BackingStoreVersion: 1,
97 | }
98 |
99 | buf := &bytes.Buffer{}
100 | encoder := NewEncoder(buf)
101 | err := encoder.Encode(data)
102 | if err != nil {
103 | fmt.Println(err)
104 | }
105 | fmt.Println(buf.String())
106 |
107 | // Output:
108 | //
109 | // CFBundleInfoDictionaryVersion6.0band-size8388608bundle-backingstore-version1diskimage-bundle-typecom.apple.diskimage.sparsebundlesize4398046511104
110 | }
111 |
112 | func ExampleMarshal_xml() {
113 | type sparseBundleHeader struct {
114 | InfoDictionaryVersion string `plist:"CFBundleInfoDictionaryVersion"`
115 | BandSize uint64 `plist:"band-size"`
116 | BackingStoreVersion int `plist:"bundle-backingstore-version"`
117 | DiskImageBundleType string `plist:"diskimage-bundle-type"`
118 | Size uint64 `plist:"size"`
119 | }
120 | data := &sparseBundleHeader{
121 | InfoDictionaryVersion: "6.0",
122 | BandSize: 8388608,
123 | Size: 4 * 1048576 * 1024 * 1024,
124 | DiskImageBundleType: "com.apple.diskimage.sparsebundle",
125 | BackingStoreVersion: 1,
126 | }
127 |
128 | plist, err := MarshalIndent(data, XMLFormat, "\t")
129 | if err != nil {
130 | fmt.Println(err)
131 | }
132 | fmt.Println(string(plist))
133 |
134 | // Output:
135 | //
136 | //
137 | //
138 | // CFBundleInfoDictionaryVersion
139 | // 6.0
140 | // band-size
141 | // 8388608
142 | // bundle-backingstore-version
143 | // 1
144 | // diskimage-bundle-type
145 | // com.apple.diskimage.sparsebundle
146 | // size
147 | // 4398046511104
148 | //
149 | //
150 | }
151 |
152 | func ExampleMarshal_gnustep() {
153 | type sparseBundleHeader struct {
154 | InfoDictionaryVersion string `plist:"CFBundleInfoDictionaryVersion"`
155 | BandSize uint64 `plist:"band-size"`
156 | BackingStoreVersion int `plist:"bundle-backingstore-version"`
157 | DiskImageBundleType string `plist:"diskimage-bundle-type"`
158 | Size uint64 `plist:"size"`
159 | }
160 | data := &sparseBundleHeader{
161 | InfoDictionaryVersion: "6.0",
162 | BandSize: 8388608,
163 | Size: 4 * 1048576 * 1024 * 1024,
164 | DiskImageBundleType: "com.apple.diskimage.sparsebundle",
165 | BackingStoreVersion: 1,
166 | }
167 |
168 | plist, err := MarshalIndent(data, GNUStepFormat, "\t")
169 | if err != nil {
170 | fmt.Println(err)
171 | }
172 | fmt.Println(string(plist))
173 |
174 | // Output: {
175 | // CFBundleInfoDictionaryVersion = 6.0;
176 | // band-size = <*I8388608>;
177 | // bundle-backingstore-version = <*I1>;
178 | // diskimage-bundle-type = com.apple.diskimage.sparsebundle;
179 | // size = <*I4398046511104>;
180 | // }
181 | }
182 |
--------------------------------------------------------------------------------
/vendor/src/github.com/DHowett/go-plist/marshal.go:
--------------------------------------------------------------------------------
1 | package plist
2 |
3 | import (
4 | "encoding"
5 | "reflect"
6 | "time"
7 | )
8 |
9 | func isEmptyValue(v reflect.Value) bool {
10 | switch v.Kind() {
11 | case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
12 | return v.Len() == 0
13 | case reflect.Bool:
14 | return !v.Bool()
15 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
16 | return v.Int() == 0
17 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
18 | return v.Uint() == 0
19 | case reflect.Float32, reflect.Float64:
20 | return v.Float() == 0
21 | case reflect.Interface, reflect.Ptr:
22 | return v.IsNil()
23 | }
24 | return false
25 | }
26 |
27 | var (
28 | textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
29 | timeType = reflect.TypeOf((*time.Time)(nil)).Elem()
30 | )
31 |
32 | func (p *Encoder) marshalTextInterface(marshalable encoding.TextMarshaler) *plistValue {
33 | s, err := marshalable.MarshalText()
34 | if err != nil {
35 | panic(err)
36 | }
37 | return &plistValue{String, string(s)}
38 | }
39 |
40 | func (p *Encoder) marshalStruct(typ reflect.Type, val reflect.Value) *plistValue {
41 | tinfo, _ := getTypeInfo(typ)
42 |
43 | dict := &dictionary{
44 | m: make(map[string]*plistValue, len(tinfo.fields)),
45 | }
46 | for _, finfo := range tinfo.fields {
47 | value := finfo.value(val)
48 | if !value.IsValid() || finfo.omitEmpty && isEmptyValue(value) {
49 | continue
50 | }
51 | dict.m[finfo.name] = p.marshal(value)
52 | }
53 |
54 | return &plistValue{Dictionary, dict}
55 | }
56 |
57 | func (p *Encoder) marshalTime(val reflect.Value) *plistValue {
58 | time := val.Interface().(time.Time)
59 | return &plistValue{Date, time}
60 | }
61 |
62 | func (p *Encoder) marshal(val reflect.Value) *plistValue {
63 | if !val.IsValid() {
64 | return nil
65 | }
66 |
67 | // time.Time implements TextMarshaler, but we need to store it in RFC3339
68 | if val.Type() == timeType {
69 | return p.marshalTime(val)
70 | }
71 | if val.Kind() == reflect.Ptr || (val.Kind() == reflect.Interface && val.NumMethod() == 0) {
72 | ival := val.Elem()
73 | if ival.IsValid() && ival.Type() == timeType {
74 | return p.marshalTime(ival)
75 | }
76 | }
77 |
78 | // Check for text marshaler.
79 | if val.CanInterface() && val.Type().Implements(textMarshalerType) {
80 | return p.marshalTextInterface(val.Interface().(encoding.TextMarshaler))
81 | }
82 | if val.CanAddr() {
83 | pv := val.Addr()
84 | if pv.CanInterface() && pv.Type().Implements(textMarshalerType) {
85 | return p.marshalTextInterface(pv.Interface().(encoding.TextMarshaler))
86 | }
87 | }
88 |
89 | // Descend into pointers or interfaces
90 | if val.Kind() == reflect.Ptr || (val.Kind() == reflect.Interface && val.NumMethod() == 0) {
91 | val = val.Elem()
92 | }
93 |
94 | // We got this far and still may have an invalid anything or nil ptr/interface
95 | if !val.IsValid() || ((val.Kind() == reflect.Ptr || val.Kind() == reflect.Interface) && val.IsNil()) {
96 | return nil
97 | }
98 |
99 | typ := val.Type()
100 |
101 | if val.Kind() == reflect.Struct {
102 | return p.marshalStruct(typ, val)
103 | }
104 |
105 | switch val.Kind() {
106 | case reflect.String:
107 | return &plistValue{String, val.String()}
108 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
109 | return &plistValue{Integer, signedInt{uint64(val.Int()), true}}
110 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
111 | return &plistValue{Integer, signedInt{uint64(val.Uint()), false}}
112 | case reflect.Float32, reflect.Float64:
113 | return &plistValue{Real, sizedFloat{val.Float(), val.Type().Bits()}}
114 | case reflect.Bool:
115 | return &plistValue{Boolean, val.Bool()}
116 | case reflect.Slice, reflect.Array:
117 | if typ.Elem().Kind() == reflect.Uint8 {
118 | bytes := []byte(nil)
119 | if val.CanAddr() {
120 | bytes = val.Bytes()
121 | } else {
122 | bytes = make([]byte, val.Len())
123 | reflect.Copy(reflect.ValueOf(bytes), val)
124 | }
125 | return &plistValue{Data, bytes}
126 | } else {
127 | subvalues := make([]*plistValue, val.Len())
128 | for idx, length := 0, val.Len(); idx < length; idx++ {
129 | if subpval := p.marshal(val.Index(idx)); subpval != nil {
130 | subvalues[idx] = subpval
131 | }
132 | }
133 | return &plistValue{Array, subvalues}
134 | }
135 | case reflect.Map:
136 | if typ.Key().Kind() != reflect.String {
137 | panic(&unknownTypeError{typ})
138 | }
139 |
140 | l := val.Len()
141 | dict := &dictionary{
142 | m: make(map[string]*plistValue, l),
143 | }
144 | for _, keyv := range val.MapKeys() {
145 | if subpval := p.marshal(val.MapIndex(keyv)); subpval != nil {
146 | dict.m[keyv.String()] = subpval
147 | }
148 | }
149 | return &plistValue{Dictionary, dict}
150 | default:
151 | panic(&unknownTypeError{typ})
152 | }
153 | return nil
154 | }
155 |
--------------------------------------------------------------------------------
/vendor/src/github.com/DHowett/go-plist/marshal_test.go:
--------------------------------------------------------------------------------
1 | package plist
2 |
3 | import (
4 | "reflect"
5 | "testing"
6 | "time"
7 | )
8 |
9 | func BenchmarkStructMarshal(b *testing.B) {
10 | for i := 0; i < b.N; i++ {
11 | e := &Encoder{}
12 | e.marshal(reflect.ValueOf(plistValueTreeRawData))
13 | }
14 | }
15 |
16 | func BenchmarkMapMarshal(b *testing.B) {
17 | data := map[string]interface{}{
18 | "intarray": []interface{}{
19 | int(1),
20 | int8(8),
21 | int16(16),
22 | int32(32),
23 | int64(64),
24 | uint(2),
25 | uint8(9),
26 | uint16(17),
27 | uint32(33),
28 | uint64(65),
29 | },
30 | "floats": []interface{}{
31 | float32(32.0),
32 | float64(64.0),
33 | },
34 | "booleans": []bool{
35 | true,
36 | false,
37 | },
38 | "strings": []string{
39 | "Hello, ASCII",
40 | "Hello, 世界",
41 | },
42 | "data": []byte{1, 2, 3, 4},
43 | "date": time.Date(2013, 11, 27, 0, 34, 0, 0, time.UTC),
44 | }
45 | b.ResetTimer()
46 | for i := 0; i < b.N; i++ {
47 | e := &Encoder{}
48 | e.marshal(reflect.ValueOf(data))
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/vendor/src/github.com/DHowett/go-plist/must.go:
--------------------------------------------------------------------------------
1 | package plist
2 |
3 | import (
4 | "io"
5 | "strconv"
6 | )
7 |
8 | type mustWriter struct {
9 | io.Writer
10 | }
11 |
12 | func (w mustWriter) Write(p []byte) (int, error) {
13 | n, err := w.Writer.Write(p)
14 | if err != nil {
15 | panic(err)
16 | }
17 | return n, nil
18 | }
19 |
20 | func mustParseInt(str string, base, bits int) int64 {
21 | i, err := strconv.ParseInt(str, base, bits)
22 | if err != nil {
23 | panic(err)
24 | }
25 | return i
26 | }
27 |
28 | func mustParseUint(str string, base, bits int) uint64 {
29 | i, err := strconv.ParseUint(str, base, bits)
30 | if err != nil {
31 | panic(err)
32 | }
33 | return i
34 | }
35 |
36 | func mustParseFloat(str string, bits int) float64 {
37 | i, err := strconv.ParseFloat(str, bits)
38 | if err != nil {
39 | panic(err)
40 | }
41 | return i
42 | }
43 |
44 | func mustParseBool(str string) bool {
45 | i, err := strconv.ParseBool(str)
46 | if err != nil {
47 | panic(err)
48 | }
49 | return i
50 | }
51 |
--------------------------------------------------------------------------------
/vendor/src/github.com/DHowett/go-plist/plist.go:
--------------------------------------------------------------------------------
1 | package plist
2 |
3 | import (
4 | "reflect"
5 | "sort"
6 | )
7 |
8 | // Property list format constants
9 | const (
10 | // Used by Decoder to represent an invalid property list.
11 | InvalidFormat int = 0
12 |
13 | // Used to indicate total abandon with regards to Encoder's output format.
14 | AutomaticFormat = 0
15 |
16 | XMLFormat = 1
17 | BinaryFormat = 2
18 | OpenStepFormat = 3
19 | GNUStepFormat = 4
20 | )
21 |
22 | var FormatNames = map[int]string{
23 | InvalidFormat: "unknown/invalid",
24 | XMLFormat: "XML",
25 | BinaryFormat: "Binary",
26 | OpenStepFormat: "OpenStep",
27 | GNUStepFormat: "GNUStep",
28 | }
29 |
30 | type plistKind uint
31 |
32 | const (
33 | Invalid plistKind = iota
34 | Dictionary
35 | Array
36 | String
37 | Integer
38 | Real
39 | Boolean
40 | Data
41 | Date
42 | )
43 |
44 | var plistKindNames map[plistKind]string = map[plistKind]string{
45 | Invalid: "invalid",
46 | Dictionary: "dictionary",
47 | Array: "array",
48 | String: "string",
49 | Integer: "integer",
50 | Real: "real",
51 | Boolean: "boolean",
52 | Data: "data",
53 | Date: "date",
54 | }
55 |
56 | type plistValue struct {
57 | kind plistKind
58 | value interface{}
59 | }
60 |
61 | type signedInt struct {
62 | value uint64
63 | signed bool
64 | }
65 |
66 | type sizedFloat struct {
67 | value float64
68 | bits int
69 | }
70 |
71 | type dictionary struct {
72 | count int
73 | m map[string]*plistValue
74 | keys sort.StringSlice
75 | values []*plistValue
76 | }
77 |
78 | func (d *dictionary) Len() int {
79 | return d.count
80 | }
81 |
82 | func (d *dictionary) Less(i, j int) bool {
83 | return d.keys.Less(i, j)
84 | }
85 |
86 | func (d *dictionary) Swap(i, j int) {
87 | d.keys.Swap(i, j)
88 | d.values[i], d.values[j] = d.values[j], d.values[i]
89 | }
90 |
91 | func (d *dictionary) populateArrays() {
92 | if d.count > 0 {
93 | return
94 | }
95 |
96 | l := len(d.m)
97 | d.count = l
98 | d.keys = make([]string, l)
99 | d.values = make([]*plistValue, l)
100 | i := 0
101 | for k, v := range d.m {
102 | d.keys[i] = k
103 | d.values[i] = v
104 | i++
105 | }
106 | sort.Sort(d)
107 | }
108 |
109 | type unknownTypeError struct {
110 | typ reflect.Type
111 | }
112 |
113 | func (u *unknownTypeError) Error() string {
114 | return "plist: can't marshal value of type " + u.typ.String()
115 | }
116 |
117 | type invalidPlistError struct {
118 | format string
119 | err error
120 | }
121 |
122 | func (e invalidPlistError) Error() string {
123 | s := "plist: invalid " + e.format + " property list"
124 | if e.err != nil {
125 | s += ": " + e.err.Error()
126 | }
127 | return s
128 | }
129 |
130 | type plistParseError struct {
131 | format string
132 | err error
133 | }
134 |
135 | func (e plistParseError) Error() string {
136 | s := "plist: error parsing " + e.format + " property list"
137 | if e.err != nil {
138 | s += ": " + e.err.Error()
139 | }
140 | return s
141 | }
142 |
--------------------------------------------------------------------------------
/vendor/src/github.com/DHowett/go-plist/text.go:
--------------------------------------------------------------------------------
1 | package plist
2 |
3 | import (
4 | "bufio"
5 | "encoding/hex"
6 | "errors"
7 | "io"
8 | "runtime"
9 | "strconv"
10 | "strings"
11 | "time"
12 | )
13 |
14 | type textPlistGenerator struct {
15 | writer io.Writer
16 | format int
17 |
18 | quotableTable *[4]uint64
19 |
20 | indent string
21 | depth int
22 |
23 | dictKvDelimiter, dictEntryDelimiter, arrayDelimiter []byte
24 | }
25 |
26 | var (
27 | textPlistTimeLayout = "2006-01-02 15:04:05 -0700"
28 | padding = "0000"
29 | )
30 |
31 | func (p *textPlistGenerator) generateDocument(pval *plistValue) {
32 | p.writePlistValue(pval)
33 | }
34 |
35 | func (p *textPlistGenerator) plistQuotedString(str string) string {
36 | if str == "" {
37 | return `""`
38 | }
39 | s := ""
40 | quot := false
41 | for _, r := range str {
42 | if r > 0xFF {
43 | quot = true
44 | s += `\U`
45 | us := strconv.FormatInt(int64(r), 16)
46 | s += padding[len(us):]
47 | s += us
48 | } else if r > 0x7F {
49 | quot = true
50 | s += `\`
51 | us := strconv.FormatInt(int64(r), 8)
52 | s += padding[1+len(us):]
53 | s += us
54 | } else {
55 | c := uint8(r)
56 | if (*p.quotableTable)[c/64]&(1<<(c%64)) > 0 {
57 | quot = true
58 | }
59 |
60 | switch c {
61 | case '\a':
62 | s += `\a`
63 | case '\b':
64 | s += `\b`
65 | case '\v':
66 | s += `\v`
67 | case '\f':
68 | s += `\f`
69 | case '\\':
70 | s += `\\`
71 | case '"':
72 | s += `\"`
73 | case '\t', '\r', '\n':
74 | fallthrough
75 | default:
76 | s += string(c)
77 | }
78 | }
79 | }
80 | if quot {
81 | s = `"` + s + `"`
82 | }
83 | return s
84 | }
85 |
86 | func (p *textPlistGenerator) deltaIndent(depthDelta int) {
87 | if depthDelta < 0 {
88 | p.depth--
89 | } else if depthDelta > 0 {
90 | p.depth++
91 | }
92 | }
93 |
94 | func (p *textPlistGenerator) writeIndent() {
95 | if len(p.indent) == 0 {
96 | return
97 | }
98 | if len(p.indent) > 0 {
99 | p.writer.Write([]byte("\n"))
100 | for i := 0; i < p.depth; i++ {
101 | io.WriteString(p.writer, p.indent)
102 | }
103 | }
104 | }
105 |
106 | func (p *textPlistGenerator) writePlistValue(pval *plistValue) {
107 | if pval == nil {
108 | return
109 | }
110 |
111 | switch pval.kind {
112 | case Dictionary:
113 | p.writer.Write([]byte(`{`))
114 | p.deltaIndent(1)
115 | dict := pval.value.(*dictionary)
116 | dict.populateArrays()
117 | for i, k := range dict.keys {
118 | p.writeIndent()
119 | io.WriteString(p.writer, p.plistQuotedString(k))
120 | p.writer.Write(p.dictKvDelimiter)
121 | p.writePlistValue(dict.values[i])
122 | p.writer.Write(p.dictEntryDelimiter)
123 | }
124 | p.deltaIndent(-1)
125 | p.writeIndent()
126 | p.writer.Write([]byte(`}`))
127 | case Array:
128 | p.writer.Write([]byte(`(`))
129 | p.deltaIndent(1)
130 | values := pval.value.([]*plistValue)
131 | for _, v := range values {
132 | p.writeIndent()
133 | p.writePlistValue(v)
134 | p.writer.Write(p.arrayDelimiter)
135 | }
136 | p.deltaIndent(-1)
137 | p.writeIndent()
138 | p.writer.Write([]byte(`)`))
139 | case String:
140 | io.WriteString(p.writer, p.plistQuotedString(pval.value.(string)))
141 | case Integer:
142 | if p.format == GNUStepFormat {
143 | p.writer.Write([]byte(`<*I`))
144 | }
145 | if pval.value.(signedInt).signed {
146 | io.WriteString(p.writer, strconv.FormatInt(int64(pval.value.(signedInt).value), 10))
147 | } else {
148 | io.WriteString(p.writer, strconv.FormatUint(pval.value.(signedInt).value, 10))
149 | }
150 | if p.format == GNUStepFormat {
151 | p.writer.Write([]byte(`>`))
152 | }
153 | case Real:
154 | if p.format == GNUStepFormat {
155 | p.writer.Write([]byte(`<*R`))
156 | }
157 | io.WriteString(p.writer, strconv.FormatFloat(pval.value.(sizedFloat).value, 'g', -1, 64))
158 | if p.format == GNUStepFormat {
159 | p.writer.Write([]byte(`>`))
160 | }
161 | case Boolean:
162 | b := pval.value.(bool)
163 | if p.format == GNUStepFormat {
164 | if b {
165 | p.writer.Write([]byte(`<*BY>`))
166 | } else {
167 | p.writer.Write([]byte(`<*BN>`))
168 | }
169 | } else {
170 | if b {
171 | p.writer.Write([]byte(`1`))
172 | } else {
173 | p.writer.Write([]byte(`0`))
174 | }
175 | }
176 | case Data:
177 | b := pval.value.([]byte)
178 | var hexencoded [9]byte
179 | var l int
180 | var asc = 9
181 | hexencoded[8] = ' '
182 |
183 | p.writer.Write([]byte(`<`))
184 | for i := 0; i < len(b); i += 4 {
185 | l = i + 4
186 | if l >= len(b) {
187 | l = len(b)
188 | // We no longer need the space - or the rest of the buffer.
189 | // (we used >= above to get this part without another conditional :P)
190 | asc = (l - i) * 2
191 | }
192 | // Fill the buffer (only up to 8 characters, to preserve the space we implicitly include
193 | // at the end of every encode)
194 | hex.Encode(hexencoded[:8], b[i:l])
195 | io.WriteString(p.writer, string(hexencoded[:asc]))
196 | }
197 | p.writer.Write([]byte(`>`))
198 | case Date:
199 | if p.format == GNUStepFormat {
200 | p.writer.Write([]byte(`<*D`))
201 | io.WriteString(p.writer, pval.value.(time.Time).In(time.UTC).Format(textPlistTimeLayout))
202 | p.writer.Write([]byte(`>`))
203 | } else {
204 | io.WriteString(p.writer, p.plistQuotedString(pval.value.(time.Time).In(time.UTC).Format(textPlistTimeLayout)))
205 | }
206 | }
207 | }
208 |
209 | func (p *textPlistGenerator) Indent(i string) {
210 | p.indent = i
211 | if i == "" {
212 | p.dictKvDelimiter = []byte(`=`)
213 | } else {
214 | // For pretty-printing
215 | p.dictKvDelimiter = []byte(` = `)
216 | }
217 | }
218 |
219 | func newTextPlistGenerator(w io.Writer, format int) *textPlistGenerator {
220 | table := &osQuotable
221 | if format == GNUStepFormat {
222 | table = &gsQuotable
223 | }
224 | return &textPlistGenerator{
225 | writer: mustWriter{w},
226 | format: format,
227 | quotableTable: table,
228 | dictKvDelimiter: []byte(`=`),
229 | arrayDelimiter: []byte(`,`),
230 | dictEntryDelimiter: []byte(`;`),
231 | }
232 | }
233 |
234 | type byteReader interface {
235 | io.Reader
236 | io.ByteScanner
237 | ReadBytes(delim byte) ([]byte, error)
238 | }
239 |
240 | type textPlistParser struct {
241 | reader byteReader
242 | whitespaceReplacer *strings.Replacer
243 | format int
244 | }
245 |
246 | func (p *textPlistParser) parseDocument() (pval *plistValue, parseError error) {
247 | defer func() {
248 | if r := recover(); r != nil {
249 | if _, ok := r.(runtime.Error); ok {
250 | panic(r)
251 | }
252 | if _, ok := r.(invalidPlistError); ok {
253 | parseError = r.(error)
254 | } else {
255 | // Wrap all non-invalid-plist errors.
256 | parseError = plistParseError{"text", r.(error)}
257 | }
258 | }
259 | }()
260 | pval = p.parsePlistValue()
261 | return
262 | }
263 |
264 | func (p *textPlistParser) chugWhitespace() {
265 | for {
266 | c, err := p.reader.ReadByte()
267 | if err != nil && err != io.EOF {
268 | panic(err)
269 | }
270 | if whitespace[c/64]&(1<<(c%64)) == 0 {
271 | if c == '/' && err != io.EOF {
272 | // A / at the end of the file is not the begining of a comment.
273 | c, err = p.reader.ReadByte()
274 | if err != nil && err != io.EOF {
275 | panic(err)
276 | }
277 | switch c {
278 | case '/':
279 | for {
280 | c, err = p.reader.ReadByte()
281 | if err != nil && err != io.EOF {
282 | panic(err)
283 | } else if err == io.EOF {
284 | break
285 | }
286 | // TODO: UTF-8
287 | if c == '\n' || c == '\r' {
288 | break
289 | }
290 | }
291 | case '*':
292 | star := false
293 | for {
294 | c, err = p.reader.ReadByte()
295 | if err != nil {
296 | panic(err)
297 | }
298 | if c == '*' {
299 | star = true
300 | } else if c == '/' && star {
301 | break
302 | } else {
303 | star = false
304 | }
305 | }
306 | }
307 | continue
308 | }
309 | p.reader.UnreadByte()
310 | break
311 | }
312 | }
313 | }
314 |
315 | func (p *textPlistParser) parseQuotedString() *plistValue {
316 | escaping := false
317 | s := ""
318 | for {
319 | byt, err := p.reader.ReadByte()
320 | // EOF here is an error: we're inside a quoted string!
321 | if err != nil {
322 | panic(err)
323 | }
324 | c := rune(byt)
325 | if !escaping {
326 | if c == '"' {
327 | break
328 | } else if c == '\\' {
329 | escaping = true
330 | continue
331 | }
332 | } else {
333 | escaping = false
334 | // Everything that is not listed here passes through unharmed.
335 | switch c {
336 | case 'a':
337 | c = '\a'
338 | case 'b':
339 | c = '\b'
340 | case 'v':
341 | c = '\v'
342 | case 'f':
343 | c = '\f'
344 | case 't':
345 | c = '\t'
346 | case 'r':
347 | c = '\r'
348 | case 'n':
349 | c = '\n'
350 | case 'x', 'u', 'U': // hex and unicode
351 | l := 4
352 | if c == 'x' {
353 | l = 2
354 | }
355 | hex := make([]byte, l)
356 | p.reader.Read(hex)
357 | newc := mustParseInt(string(hex), 16, 16)
358 | c = rune(newc)
359 | case '0', '1', '2', '3', '4', '5', '6', '7': // octal!
360 | oct := make([]byte, 3)
361 | oct[0] = uint8(c)
362 | p.reader.Read(oct[1:])
363 | newc := mustParseInt(string(oct), 8, 16)
364 | c = rune(newc)
365 | }
366 | }
367 | s += string(c)
368 | }
369 | return &plistValue{String, s}
370 | }
371 |
372 | func (p *textPlistParser) parseUnquotedString() *plistValue {
373 | s := ""
374 | for {
375 | c, err := p.reader.ReadByte()
376 | if err != nil {
377 | if err == io.EOF {
378 | break
379 | }
380 | panic(err)
381 | }
382 | // if we encounter a character that must be quoted, we're done.
383 | // the GNUStep quote table is more lax here, so we use it instead of the OpenStep one.
384 | if gsQuotable[c/64]&(1<<(c%64)) > 0 {
385 | p.reader.UnreadByte()
386 | break
387 | }
388 | s += string(c)
389 | }
390 | return &plistValue{String, s}
391 | }
392 |
393 | func (p *textPlistParser) parseDictionary() *plistValue {
394 | var keypv *plistValue
395 | subval := make(map[string]*plistValue)
396 | for {
397 | p.chugWhitespace()
398 |
399 | c, err := p.reader.ReadByte()
400 | // EOF here is an error: we're inside a dictionary!
401 | if err != nil {
402 | panic(err)
403 | }
404 |
405 | if c == '}' {
406 | break
407 | } else if c == '"' {
408 | keypv = p.parseQuotedString()
409 | } else {
410 | p.reader.UnreadByte() // Whoops, ate part of the string
411 | keypv = p.parseUnquotedString()
412 | }
413 | if keypv == nil || keypv.value.(string) == "" {
414 | // TODO better error
415 | panic(errors.New("missing dictionary key"))
416 | }
417 |
418 | p.chugWhitespace()
419 | c, err = p.reader.ReadByte()
420 | if err != nil {
421 | panic(err)
422 | }
423 |
424 | if c != '=' {
425 | panic(errors.New("missing = in dictionary"))
426 | }
427 |
428 | // whitespace is guzzled within
429 | val := p.parsePlistValue()
430 |
431 | p.chugWhitespace()
432 | c, err = p.reader.ReadByte()
433 | if err != nil {
434 | panic(err)
435 | }
436 |
437 | if c != ';' {
438 | panic(errors.New("missing ; in dictionary"))
439 | }
440 |
441 | subval[keypv.value.(string)] = val
442 | }
443 | return &plistValue{Dictionary, &dictionary{m: subval}}
444 | }
445 |
446 | func (p *textPlistParser) parseArray() *plistValue {
447 | subval := make([]*plistValue, 0, 10)
448 | for {
449 | c, err := p.reader.ReadByte()
450 | // EOF here is an error: we're inside an array!
451 | if err != nil {
452 | panic(err)
453 | }
454 |
455 | if c == ')' {
456 | break
457 | } else if c == ',' {
458 | continue
459 | }
460 |
461 | p.reader.UnreadByte()
462 | pval := p.parsePlistValue()
463 | if pval.kind == String && pval.value.(string) == "" {
464 | continue
465 | }
466 | subval = append(subval, pval)
467 | }
468 | return &plistValue{Array, subval}
469 | }
470 |
471 | func (p *textPlistParser) parseGNUStepValue(v []byte) *plistValue {
472 | if len(v) < 2 {
473 | panic(errors.New("invalid GNUStep extended value"))
474 | }
475 | typ := v[1]
476 | v = v[2:]
477 | switch typ {
478 | case 'I':
479 | if v[0] == '-' {
480 | n := mustParseInt(string(v), 10, 64)
481 | return &plistValue{Integer, signedInt{uint64(n), true}}
482 | } else {
483 | n := mustParseUint(string(v), 10, 64)
484 | return &plistValue{Integer, signedInt{n, false}}
485 | }
486 | case 'R':
487 | n := mustParseFloat(string(v), 64)
488 | return &plistValue{Real, sizedFloat{n, 64}}
489 | case 'B':
490 | b := v[0] == 'Y'
491 | return &plistValue{Boolean, b}
492 | case 'D':
493 | t, err := time.Parse(textPlistTimeLayout, string(v))
494 | if err != nil {
495 | panic(err)
496 | }
497 |
498 | return &plistValue{Date, t.In(time.UTC)}
499 | }
500 | panic(errors.New("invalid GNUStep type " + string(typ)))
501 | return nil
502 | }
503 |
504 | func (p *textPlistParser) parsePlistValue() *plistValue {
505 | for {
506 | p.chugWhitespace()
507 |
508 | c, err := p.reader.ReadByte()
509 | if err != nil && err != io.EOF {
510 | panic(err)
511 | }
512 | switch c {
513 | case '<':
514 | bytes, err := p.reader.ReadBytes('>')
515 | if err != nil {
516 | panic(err)
517 | }
518 | bytes = bytes[:len(bytes)-1]
519 |
520 | if bytes[0] == '*' {
521 | p.format = GNUStepFormat
522 | return p.parseGNUStepValue(bytes)
523 | } else {
524 | s := p.whitespaceReplacer.Replace(string(bytes))
525 | data, err := hex.DecodeString(s)
526 | if err != nil {
527 | panic(err)
528 | }
529 | return &plistValue{Data, data}
530 | }
531 | case '"':
532 | return p.parseQuotedString()
533 | case '{':
534 | return p.parseDictionary()
535 | case '(':
536 | return p.parseArray()
537 | default:
538 | p.reader.UnreadByte() // Place back in buffer for parseUnquotedString
539 | return p.parseUnquotedString()
540 | }
541 | }
542 | return nil
543 | }
544 |
545 | func newTextPlistParser(r io.Reader) *textPlistParser {
546 | var reader byteReader
547 | if rd, ok := r.(byteReader); ok {
548 | reader = rd
549 | } else {
550 | reader = bufio.NewReader(r)
551 | }
552 | return &textPlistParser{
553 | reader: reader,
554 | whitespaceReplacer: strings.NewReplacer("\t", "", "\n", "", " ", "", "\r", ""),
555 | format: OpenStepFormat,
556 | }
557 | }
558 |
--------------------------------------------------------------------------------
/vendor/src/github.com/DHowett/go-plist/text_tables.go:
--------------------------------------------------------------------------------
1 | package plist
2 |
3 | // Bitmap of characters that must be inside a quoted string
4 | // when written to an old-style property list
5 | // Low bits represent lower characters, and each uint64 represents 64 characters.
6 | var gsQuotable = [4]uint64{
7 | 0x78001385ffffffff,
8 | 0xa800000138000000,
9 | 0xffffffffffffffff,
10 | 0xffffffffffffffff,
11 | }
12 |
13 | // 7f instead of 3f in the top line: CFOldStylePlist.c says . is valid, but they quote it.
14 | var osQuotable = [4]uint64{
15 | 0xf4007f6fffffffff,
16 | 0xf8000001f8000001,
17 | 0xffffffffffffffff,
18 | 0xffffffffffffffff,
19 | }
20 |
21 | var whitespace = [4]uint64{
22 | 0x0000000100003f00,
23 | 0x0000000000000000,
24 | 0x0000000000000000,
25 | 0x0000000000000000,
26 | }
27 |
--------------------------------------------------------------------------------
/vendor/src/github.com/DHowett/go-plist/text_test.go:
--------------------------------------------------------------------------------
1 | package plist
2 |
3 | import (
4 | "bytes"
5 | "io/ioutil"
6 | "testing"
7 | )
8 |
9 | func BenchmarkOpenStepGenerate(b *testing.B) {
10 | for i := 0; i < b.N; i++ {
11 | d := newTextPlistGenerator(ioutil.Discard, OpenStepFormat)
12 | d.generateDocument(plistValueTree)
13 | }
14 | }
15 |
16 | func BenchmarkOpenStepParse(b *testing.B) {
17 | buf := bytes.NewReader([]byte(plistValueTreeAsOpenStep))
18 | b.ResetTimer()
19 | for i := 0; i < b.N; i++ {
20 | b.StartTimer()
21 | d := newTextPlistParser(buf)
22 | d.parseDocument()
23 | b.StopTimer()
24 | buf.Seek(0, 0)
25 | }
26 | }
27 |
28 | func BenchmarkGNUStepParse(b *testing.B) {
29 | buf := bytes.NewReader([]byte(plistValueTreeAsGNUStep))
30 | b.ResetTimer()
31 | for i := 0; i < b.N; i++ {
32 | b.StartTimer()
33 | d := newTextPlistParser(buf)
34 | d.parseDocument()
35 | b.StopTimer()
36 | buf.Seek(0, 0)
37 | }
38 | }
39 |
40 | func TestTextCommentDecode(t *testing.T) {
41 | var testData = "{A=1 /* A is 1 because it is the first letter */;\nB=2; // B is 2 because comment-to-end-of-line.\nC=3;}"
42 | type D struct{ A, B, C int }
43 | actual := D{1, 2, 3}
44 | var parsed D
45 | buf := bytes.NewReader([]byte(testData))
46 | decoder := NewDecoder(buf)
47 | err := decoder.Decode(&parsed)
48 | if err != nil {
49 | t.Error(err.Error())
50 | }
51 |
52 | if actual != parsed {
53 | t.Logf("Expected: %#v", actual)
54 | t.Logf("Received: %#v", parsed)
55 | t.Fail()
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/vendor/src/github.com/DHowett/go-plist/typeinfo.go:
--------------------------------------------------------------------------------
1 | package plist
2 |
3 | import (
4 | "reflect"
5 | "strings"
6 | "sync"
7 | )
8 |
9 | // typeInfo holds details for the plist representation of a type.
10 | type typeInfo struct {
11 | fields []fieldInfo
12 | }
13 |
14 | // fieldInfo holds details for the plist representation of a single field.
15 | type fieldInfo struct {
16 | idx []int
17 | name string
18 | omitEmpty bool
19 | }
20 |
21 | var tinfoMap = make(map[reflect.Type]*typeInfo)
22 | var tinfoLock sync.RWMutex
23 |
24 | // getTypeInfo returns the typeInfo structure with details necessary
25 | // for marshalling and unmarshalling typ.
26 | func getTypeInfo(typ reflect.Type) (*typeInfo, error) {
27 | tinfoLock.RLock()
28 | tinfo, ok := tinfoMap[typ]
29 | tinfoLock.RUnlock()
30 | if ok {
31 | return tinfo, nil
32 | }
33 | tinfo = &typeInfo{}
34 | if typ.Kind() == reflect.Struct {
35 | n := typ.NumField()
36 | for i := 0; i < n; i++ {
37 | f := typ.Field(i)
38 | if f.PkgPath != "" || f.Tag.Get("plist") == "-" {
39 | continue // Private field
40 | }
41 |
42 | // For embedded structs, embed its fields.
43 | if f.Anonymous {
44 | t := f.Type
45 | if t.Kind() == reflect.Ptr {
46 | t = t.Elem()
47 | }
48 | if t.Kind() == reflect.Struct {
49 | inner, err := getTypeInfo(t)
50 | if err != nil {
51 | return nil, err
52 | }
53 | for _, finfo := range inner.fields {
54 | finfo.idx = append([]int{i}, finfo.idx...)
55 | if err := addFieldInfo(typ, tinfo, &finfo); err != nil {
56 | return nil, err
57 | }
58 | }
59 | continue
60 | }
61 | }
62 |
63 | finfo, err := structFieldInfo(typ, &f)
64 | if err != nil {
65 | return nil, err
66 | }
67 |
68 | // Add the field if it doesn't conflict with other fields.
69 | if err := addFieldInfo(typ, tinfo, finfo); err != nil {
70 | return nil, err
71 | }
72 | }
73 | }
74 | tinfoLock.Lock()
75 | tinfoMap[typ] = tinfo
76 | tinfoLock.Unlock()
77 | return tinfo, nil
78 | }
79 |
80 | // structFieldInfo builds and returns a fieldInfo for f.
81 | func structFieldInfo(typ reflect.Type, f *reflect.StructField) (*fieldInfo, error) {
82 | finfo := &fieldInfo{idx: f.Index}
83 |
84 | // Split the tag from the xml namespace if necessary.
85 | tag := f.Tag.Get("plist")
86 |
87 | // Parse flags.
88 | tokens := strings.Split(tag, ",")
89 | tag = tokens[0]
90 | if len(tokens) > 1 {
91 | tag = tokens[0]
92 | for _, flag := range tokens[1:] {
93 | switch flag {
94 | case "omitempty":
95 | finfo.omitEmpty = true
96 | }
97 | }
98 | }
99 |
100 | if tag == "" {
101 | // If the name part of the tag is completely empty,
102 | // use the field name
103 | finfo.name = f.Name
104 | return finfo, nil
105 | }
106 |
107 | finfo.name = tag
108 | return finfo, nil
109 | }
110 |
111 | // addFieldInfo adds finfo to tinfo.fields if there are no
112 | // conflicts, or if conflicts arise from previous fields that were
113 | // obtained from deeper embedded structures than finfo. In the latter
114 | // case, the conflicting entries are dropped.
115 | // A conflict occurs when the path (parent + name) to a field is
116 | // itself a prefix of another path, or when two paths match exactly.
117 | // It is okay for field paths to share a common, shorter prefix.
118 | func addFieldInfo(typ reflect.Type, tinfo *typeInfo, newf *fieldInfo) error {
119 | var conflicts []int
120 | // First, figure all conflicts. Most working code will have none.
121 | for i := range tinfo.fields {
122 | oldf := &tinfo.fields[i]
123 | if newf.name == oldf.name {
124 | conflicts = append(conflicts, i)
125 | }
126 | }
127 |
128 | // Without conflicts, add the new field and return.
129 | if conflicts == nil {
130 | tinfo.fields = append(tinfo.fields, *newf)
131 | return nil
132 | }
133 |
134 | // If any conflict is shallower, ignore the new field.
135 | // This matches the Go field resolution on embedding.
136 | for _, i := range conflicts {
137 | if len(tinfo.fields[i].idx) < len(newf.idx) {
138 | return nil
139 | }
140 | }
141 |
142 | // Otherwise, the new field is shallower, and thus takes precedence,
143 | // so drop the conflicting fields from tinfo and append the new one.
144 | for c := len(conflicts) - 1; c >= 0; c-- {
145 | i := conflicts[c]
146 | copy(tinfo.fields[i:], tinfo.fields[i+1:])
147 | tinfo.fields = tinfo.fields[:len(tinfo.fields)-1]
148 | }
149 | tinfo.fields = append(tinfo.fields, *newf)
150 | return nil
151 | }
152 |
153 | // value returns v's field value corresponding to finfo.
154 | // It's equivalent to v.FieldByIndex(finfo.idx), but initializes
155 | // and dereferences pointers as necessary.
156 | func (finfo *fieldInfo) value(v reflect.Value) reflect.Value {
157 | for i, x := range finfo.idx {
158 | if i > 0 {
159 | t := v.Type()
160 | if t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct {
161 | if v.IsNil() {
162 | v.Set(reflect.New(v.Type().Elem()))
163 | }
164 | v = v.Elem()
165 | }
166 | }
167 | v = v.Field(x)
168 | }
169 | return v
170 | }
171 |
--------------------------------------------------------------------------------
/vendor/src/github.com/DHowett/go-plist/unmarshal.go:
--------------------------------------------------------------------------------
1 | package plist
2 |
3 | import (
4 | "encoding"
5 | "fmt"
6 | "reflect"
7 | "time"
8 | )
9 |
10 | type incompatibleDecodeTypeError struct {
11 | typ reflect.Type
12 | pKind plistKind
13 | }
14 |
15 | func (u *incompatibleDecodeTypeError) Error() string {
16 | return fmt.Sprintf("plist: type mismatch: tried to decode %v into value of type %v", plistKindNames[u.pKind], u.typ)
17 | }
18 |
19 | var (
20 | textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
21 | )
22 |
23 | func isEmptyInterface(v reflect.Value) bool {
24 | return v.Kind() == reflect.Interface && v.NumMethod() == 0
25 | }
26 |
27 | func (p *Decoder) unmarshalTextInterface(pval *plistValue, unmarshalable encoding.TextUnmarshaler) {
28 | err := unmarshalable.UnmarshalText([]byte(pval.value.(string)))
29 | if err != nil {
30 | panic(err)
31 | }
32 | }
33 |
34 | func (p *Decoder) unmarshalTime(pval *plistValue, val reflect.Value) {
35 | val.Set(reflect.ValueOf(pval.value.(time.Time)))
36 | }
37 |
38 | func (p *Decoder) unmarshalLaxString(s string, val reflect.Value) {
39 | switch val.Kind() {
40 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
41 | i := mustParseInt(s, 10, 64)
42 | val.SetInt(i)
43 | return
44 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
45 | i := mustParseUint(s, 10, 64)
46 | val.SetUint(i)
47 | return
48 | case reflect.Float32, reflect.Float64:
49 | f := mustParseFloat(s, 64)
50 | val.SetFloat(f)
51 | return
52 | case reflect.Bool:
53 | b := mustParseBool(s)
54 | val.SetBool(b)
55 | return
56 | case reflect.Struct:
57 | if val.Type() == timeType {
58 | t, err := time.Parse(textPlistTimeLayout, s)
59 | if err != nil {
60 | panic(err)
61 | }
62 | val.Set(reflect.ValueOf(t.In(time.UTC)))
63 | return
64 | }
65 | fallthrough
66 | default:
67 | panic(&incompatibleDecodeTypeError{val.Type(), String})
68 | }
69 | }
70 |
71 | func (p *Decoder) unmarshal(pval *plistValue, val reflect.Value) {
72 | if pval == nil {
73 | return
74 | }
75 |
76 | if val.Kind() == reflect.Ptr {
77 | if val.IsNil() {
78 | val.Set(reflect.New(val.Type().Elem()))
79 | }
80 | val = val.Elem()
81 | }
82 |
83 | if isEmptyInterface(val) {
84 | v := p.valueInterface(pval)
85 | val.Set(reflect.ValueOf(v))
86 | return
87 | }
88 |
89 | incompatibleTypeError := &incompatibleDecodeTypeError{val.Type(), pval.kind}
90 |
91 | // time.Time implements TextMarshaler, but we need to parse it as RFC3339
92 | if pval.kind == Date {
93 | if val.Type() == timeType {
94 | p.unmarshalTime(pval, val)
95 | return
96 | }
97 | panic(incompatibleTypeError)
98 | }
99 |
100 | if val.CanInterface() && val.Type().Implements(textUnmarshalerType) && val.Type() != timeType {
101 | p.unmarshalTextInterface(pval, val.Interface().(encoding.TextUnmarshaler))
102 | return
103 | }
104 |
105 | if val.CanAddr() {
106 | pv := val.Addr()
107 | if pv.CanInterface() && pv.Type().Implements(textUnmarshalerType) && val.Type() != timeType {
108 | p.unmarshalTextInterface(pval, pv.Interface().(encoding.TextUnmarshaler))
109 | return
110 | }
111 | }
112 |
113 | typ := val.Type()
114 |
115 | switch pval.kind {
116 | case String:
117 | if val.Kind() == reflect.String {
118 | val.SetString(pval.value.(string))
119 | return
120 | }
121 | if p.lax {
122 | p.unmarshalLaxString(pval.value.(string), val)
123 | return
124 | }
125 |
126 | panic(incompatibleTypeError)
127 | case Integer:
128 | switch val.Kind() {
129 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
130 | val.SetInt(int64(pval.value.(signedInt).value))
131 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
132 | val.SetUint(pval.value.(signedInt).value)
133 | default:
134 | panic(incompatibleTypeError)
135 | }
136 | case Real:
137 | if val.Kind() == reflect.Float32 || val.Kind() == reflect.Float64 {
138 | val.SetFloat(pval.value.(sizedFloat).value)
139 | } else {
140 | panic(incompatibleTypeError)
141 | }
142 | case Boolean:
143 | if val.Kind() == reflect.Bool {
144 | val.SetBool(pval.value.(bool))
145 | } else {
146 | panic(incompatibleTypeError)
147 | }
148 | case Data:
149 | if val.Kind() == reflect.Slice && typ.Elem().Kind() == reflect.Uint8 {
150 | val.SetBytes(pval.value.([]byte))
151 | } else {
152 | panic(incompatibleTypeError)
153 | }
154 | case Array:
155 | p.unmarshalArray(pval, val)
156 | case Dictionary:
157 | p.unmarshalDictionary(pval, val)
158 | }
159 | }
160 |
161 | func (p *Decoder) unmarshalArray(pval *plistValue, val reflect.Value) {
162 | subvalues := pval.value.([]*plistValue)
163 |
164 | var n int
165 | if val.Kind() == reflect.Slice {
166 | // Slice of element values.
167 | // Grow slice.
168 | cnt := len(subvalues) + val.Len()
169 | if cnt >= val.Cap() {
170 | ncap := 2 * cnt
171 | if ncap < 4 {
172 | ncap = 4
173 | }
174 | new := reflect.MakeSlice(val.Type(), val.Len(), ncap)
175 | reflect.Copy(new, val)
176 | val.Set(new)
177 | }
178 | n = val.Len()
179 | val.SetLen(cnt)
180 | } else if val.Kind() == reflect.Array {
181 | if len(subvalues) > val.Cap() {
182 | panic(fmt.Errorf("plist: attempted to unmarshal %d values into an array of size %d", len(subvalues), val.Cap()))
183 | }
184 | } else {
185 | panic(&incompatibleDecodeTypeError{val.Type(), pval.kind})
186 | }
187 |
188 | // Recur to read element into slice.
189 | for _, sval := range subvalues {
190 | p.unmarshal(sval, val.Index(n))
191 | n++
192 | }
193 | return
194 | }
195 |
196 | func (p *Decoder) unmarshalDictionary(pval *plistValue, val reflect.Value) {
197 | typ := val.Type()
198 | switch val.Kind() {
199 | case reflect.Struct:
200 | tinfo, err := getTypeInfo(typ)
201 | if err != nil {
202 | panic(err)
203 | }
204 |
205 | subvalues := pval.value.(*dictionary).m
206 | for _, finfo := range tinfo.fields {
207 | p.unmarshal(subvalues[finfo.name], finfo.value(val))
208 | }
209 | case reflect.Map:
210 | if val.IsNil() {
211 | val.Set(reflect.MakeMap(typ))
212 | }
213 |
214 | subvalues := pval.value.(*dictionary).m
215 | for k, sval := range subvalues {
216 | keyv := reflect.ValueOf(k).Convert(typ.Key())
217 | mapElem := val.MapIndex(keyv)
218 | if !mapElem.IsValid() {
219 | mapElem = reflect.New(typ.Elem()).Elem()
220 | }
221 |
222 | p.unmarshal(sval, mapElem)
223 | val.SetMapIndex(keyv, mapElem)
224 | }
225 | default:
226 | panic(&incompatibleDecodeTypeError{typ, pval.kind})
227 | }
228 | }
229 |
230 | /* *Interface is modelled after encoding/json */
231 | func (p *Decoder) valueInterface(pval *plistValue) interface{} {
232 | switch pval.kind {
233 | case String:
234 | return pval.value.(string)
235 | case Integer:
236 | if pval.value.(signedInt).signed {
237 | return int64(pval.value.(signedInt).value)
238 | }
239 | return pval.value.(signedInt).value
240 | case Real:
241 | bits := pval.value.(sizedFloat).bits
242 | switch bits {
243 | case 32:
244 | return float32(pval.value.(sizedFloat).value)
245 | case 64:
246 | return pval.value.(sizedFloat).value
247 | }
248 | case Boolean:
249 | return pval.value.(bool)
250 | case Array:
251 | return p.arrayInterface(pval.value.([]*plistValue))
252 | case Dictionary:
253 | return p.dictionaryInterface(pval.value.(*dictionary))
254 | case Data:
255 | return pval.value.([]byte)
256 | case Date:
257 | return pval.value.(time.Time)
258 | }
259 | return nil
260 | }
261 |
262 | func (p *Decoder) arrayInterface(subvalues []*plistValue) []interface{} {
263 | out := make([]interface{}, len(subvalues))
264 | for i, subv := range subvalues {
265 | out[i] = p.valueInterface(subv)
266 | }
267 | return out
268 | }
269 |
270 | func (p *Decoder) dictionaryInterface(dict *dictionary) map[string]interface{} {
271 | out := make(map[string]interface{})
272 | for k, subv := range dict.m {
273 | out[k] = p.valueInterface(subv)
274 | }
275 | return out
276 | }
277 |
--------------------------------------------------------------------------------
/vendor/src/github.com/DHowett/go-plist/unmarshal_test.go:
--------------------------------------------------------------------------------
1 | package plist
2 |
3 | import (
4 | "reflect"
5 | "testing"
6 | "time"
7 | )
8 |
9 | func BenchmarkStructUnmarshal(b *testing.B) {
10 | type Data struct {
11 | Intarray []uint64 `plist:"intarray"`
12 | Floats []float64 `plist:"floats"`
13 | Booleans []bool `plist:"booleans"`
14 | Strings []string `plist:"strings"`
15 | Dat []byte `plist:"data"`
16 | Date time.Time `plist:"date"`
17 | }
18 | b.ResetTimer()
19 | for i := 0; i < b.N; i++ {
20 | var xval Data
21 | d := &Decoder{}
22 | d.unmarshal(plistValueTree, reflect.ValueOf(&xval))
23 | }
24 | }
25 |
26 | func BenchmarkInterfaceUnmarshal(b *testing.B) {
27 | for i := 0; i < b.N; i++ {
28 | var xval interface{}
29 | d := &Decoder{}
30 | d.unmarshal(plistValueTree, reflect.ValueOf(&xval))
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/vendor/src/github.com/DHowett/go-plist/util.go:
--------------------------------------------------------------------------------
1 | package plist
2 |
3 | import "io"
4 |
5 | type countedWriter struct {
6 | io.Writer
7 | nbytes int
8 | }
9 |
10 | func (w *countedWriter) Write(p []byte) (int, error) {
11 | n, err := w.Writer.Write(p)
12 | w.nbytes += n
13 | return n, err
14 | }
15 |
16 | func (w *countedWriter) BytesWritten() int {
17 | return w.nbytes
18 | }
19 |
--------------------------------------------------------------------------------
/vendor/src/github.com/DHowett/go-plist/xml.go:
--------------------------------------------------------------------------------
1 | package plist
2 |
3 | import (
4 | "encoding/base64"
5 | "encoding/xml"
6 | "errors"
7 | "fmt"
8 | "io"
9 | "math"
10 | "runtime"
11 | "strings"
12 | "time"
13 | )
14 |
15 | const xmlDOCTYPE = `
16 | `
17 |
18 | type xmlPlistGenerator struct {
19 | writer io.Writer
20 | xmlEncoder *xml.Encoder
21 | }
22 |
23 | func (p *xmlPlistGenerator) generateDocument(pval *plistValue) {
24 | io.WriteString(p.writer, xml.Header)
25 | io.WriteString(p.writer, xmlDOCTYPE)
26 |
27 | plistStartElement := xml.StartElement{
28 | xml.Name{"", "plist"},
29 | []xml.Attr{
30 | {xml.Name{"", "version"}, "1.0"},
31 | },
32 | }
33 |
34 | p.xmlEncoder.EncodeToken(plistStartElement)
35 |
36 | p.writePlistValue(pval)
37 |
38 | p.xmlEncoder.EncodeToken(plistStartElement.End())
39 | p.xmlEncoder.Flush()
40 | }
41 |
42 | func (p *xmlPlistGenerator) writePlistValue(pval *plistValue) {
43 | if pval == nil {
44 | return
45 | }
46 |
47 | defer p.xmlEncoder.Flush()
48 |
49 | key := ""
50 | encodedValue := pval.value
51 | switch pval.kind {
52 | case Dictionary:
53 | startElement := xml.StartElement{Name: xml.Name{Local: "dict"}}
54 | p.xmlEncoder.EncodeToken(startElement)
55 | dict := encodedValue.(*dictionary)
56 | dict.populateArrays()
57 | for i, k := range dict.keys {
58 | p.xmlEncoder.EncodeElement(k, xml.StartElement{Name: xml.Name{Local: "key"}})
59 | p.writePlistValue(dict.values[i])
60 | }
61 | p.xmlEncoder.EncodeToken(startElement.End())
62 | case Array:
63 | startElement := xml.StartElement{Name: xml.Name{Local: "array"}}
64 | p.xmlEncoder.EncodeToken(startElement)
65 | values := encodedValue.([]*plistValue)
66 | for _, v := range values {
67 | p.writePlistValue(v)
68 | }
69 | p.xmlEncoder.EncodeToken(startElement.End())
70 | case String:
71 | key = "string"
72 | case Integer:
73 | key = "integer"
74 | if pval.value.(signedInt).signed {
75 | encodedValue = int64(pval.value.(signedInt).value)
76 | } else {
77 | encodedValue = pval.value.(signedInt).value
78 | }
79 | case Real:
80 | key = "real"
81 | encodedValue = pval.value.(sizedFloat).value
82 | switch {
83 | case math.IsInf(pval.value.(sizedFloat).value, 1):
84 | encodedValue = "inf"
85 | case math.IsInf(pval.value.(sizedFloat).value, -1):
86 | encodedValue = "-inf"
87 | case math.IsNaN(pval.value.(sizedFloat).value):
88 | encodedValue = "nan"
89 | }
90 | case Boolean:
91 | key = "false"
92 | b := pval.value.(bool)
93 | if b {
94 | key = "true"
95 | }
96 | encodedValue = ""
97 | case Data:
98 | key = "data"
99 | encodedValue = xml.CharData(base64.StdEncoding.EncodeToString(pval.value.([]byte)))
100 | case Date:
101 | key = "date"
102 | encodedValue = pval.value.(time.Time).In(time.UTC).Format(time.RFC3339)
103 | }
104 | if key != "" {
105 | err := p.xmlEncoder.EncodeElement(encodedValue, xml.StartElement{Name: xml.Name{Local: key}})
106 | if err != nil {
107 | panic(err)
108 | }
109 | }
110 | }
111 |
112 | func (p *xmlPlistGenerator) Indent(i string) {
113 | p.xmlEncoder.Indent("", i)
114 | }
115 |
116 | func newXMLPlistGenerator(w io.Writer) *xmlPlistGenerator {
117 | mw := mustWriter{w}
118 | return &xmlPlistGenerator{mw, xml.NewEncoder(mw)}
119 | }
120 |
121 | type xmlPlistParser struct {
122 | reader io.Reader
123 | xmlDecoder *xml.Decoder
124 | whitespaceReplacer *strings.Replacer
125 | ntags int
126 | }
127 |
128 | func (p *xmlPlistParser) parseDocument() (pval *plistValue, parseError error) {
129 | defer func() {
130 | if r := recover(); r != nil {
131 | if _, ok := r.(runtime.Error); ok {
132 | panic(r)
133 | }
134 | if _, ok := r.(invalidPlistError); ok {
135 | parseError = r.(error)
136 | } else {
137 | // Wrap all non-invalid-plist errors.
138 | parseError = plistParseError{"XML", r.(error)}
139 | }
140 | }
141 | }()
142 | for {
143 | if token, err := p.xmlDecoder.Token(); err == nil {
144 | if element, ok := token.(xml.StartElement); ok {
145 | pval = p.parseXMLElement(element)
146 | if p.ntags == 0 {
147 | panic(invalidPlistError{"XML", errors.New("no elements encountered")})
148 | }
149 | return
150 | }
151 | } else {
152 | // The first XML parse turned out to be invalid:
153 | // we do not have an XML property list.
154 | panic(invalidPlistError{"XML", err})
155 | }
156 | }
157 | }
158 |
159 | func (p *xmlPlistParser) parseXMLElement(element xml.StartElement) *plistValue {
160 | var charData xml.CharData
161 | switch element.Name.Local {
162 | case "plist":
163 | p.ntags++
164 | for {
165 | token, err := p.xmlDecoder.Token()
166 | if err != nil {
167 | panic(err)
168 | }
169 |
170 | if el, ok := token.(xml.EndElement); ok && el.Name.Local == "plist" {
171 | break
172 | }
173 |
174 | if el, ok := token.(xml.StartElement); ok {
175 | return p.parseXMLElement(el)
176 | }
177 | }
178 | return nil
179 | case "string":
180 | p.ntags++
181 | err := p.xmlDecoder.DecodeElement(&charData, &element)
182 | if err != nil {
183 | panic(err)
184 | }
185 |
186 | return &plistValue{String, string(charData)}
187 | case "integer":
188 | p.ntags++
189 | err := p.xmlDecoder.DecodeElement(&charData, &element)
190 | if err != nil {
191 | panic(err)
192 | }
193 |
194 | s := string(charData)
195 | if s[0] == '-' {
196 | n := mustParseInt(string(charData), 10, 64)
197 | return &plistValue{Integer, signedInt{uint64(n), true}}
198 | } else {
199 | n := mustParseUint(string(charData), 10, 64)
200 | return &plistValue{Integer, signedInt{n, false}}
201 | }
202 | case "real":
203 | p.ntags++
204 | err := p.xmlDecoder.DecodeElement(&charData, &element)
205 | if err != nil {
206 | panic(err)
207 | }
208 |
209 | n := mustParseFloat(string(charData), 64)
210 | return &plistValue{Real, sizedFloat{n, 64}}
211 | case "true", "false":
212 | p.ntags++
213 | p.xmlDecoder.Skip()
214 |
215 | b := element.Name.Local == "true"
216 | return &plistValue{Boolean, b}
217 | case "date":
218 | p.ntags++
219 | err := p.xmlDecoder.DecodeElement(&charData, &element)
220 | if err != nil {
221 | panic(err)
222 | }
223 |
224 | t, err := time.ParseInLocation(time.RFC3339, string(charData), time.UTC)
225 | if err != nil {
226 | panic(err)
227 | }
228 |
229 | return &plistValue{Date, t}
230 | case "data":
231 | p.ntags++
232 | err := p.xmlDecoder.DecodeElement(&charData, &element)
233 | if err != nil {
234 | panic(err)
235 | }
236 |
237 | str := p.whitespaceReplacer.Replace(string(charData))
238 |
239 | l := base64.StdEncoding.DecodedLen(len(str))
240 | bytes := make([]uint8, l)
241 | l, err = base64.StdEncoding.Decode(bytes, []byte(str))
242 | if err != nil {
243 | panic(err)
244 | }
245 |
246 | return &plistValue{Data, bytes[:l]}
247 | case "dict":
248 | p.ntags++
249 | var key string
250 | var subvalues map[string]*plistValue = make(map[string]*plistValue)
251 | for {
252 | token, err := p.xmlDecoder.Token()
253 | if err != nil {
254 | panic(err)
255 | }
256 |
257 | if el, ok := token.(xml.EndElement); ok && el.Name.Local == "dict" {
258 | if key != "" {
259 | panic(errors.New("missing value in dictionary"))
260 | }
261 | break
262 | }
263 |
264 | if el, ok := token.(xml.StartElement); ok {
265 | if el.Name.Local == "key" {
266 | p.xmlDecoder.DecodeElement(&key, &el)
267 | } else {
268 | if key == "" {
269 | panic(errors.New("missing key in dictionary"))
270 | }
271 | subvalues[key] = p.parseXMLElement(el)
272 | key = ""
273 | }
274 | }
275 | }
276 | return &plistValue{Dictionary, &dictionary{m: subvalues}}
277 | case "array":
278 | p.ntags++
279 | var subvalues []*plistValue = make([]*plistValue, 0, 10)
280 | for {
281 | token, err := p.xmlDecoder.Token()
282 | if err != nil {
283 | panic(err)
284 | }
285 |
286 | if el, ok := token.(xml.EndElement); ok && el.Name.Local == "array" {
287 | break
288 | }
289 |
290 | if el, ok := token.(xml.StartElement); ok {
291 | subvalues = append(subvalues, p.parseXMLElement(el))
292 | }
293 | }
294 | return &plistValue{Array, subvalues}
295 | }
296 | err := fmt.Errorf("encountered unknown element %s", element.Name.Local)
297 | if p.ntags == 0 {
298 | // If out first XML tag is invalid, it might be an openstep data element, ala or <0101>
299 | panic(invalidPlistError{"XML", err})
300 | }
301 | panic(err)
302 | }
303 |
304 | func newXMLPlistParser(r io.Reader) *xmlPlistParser {
305 | return &xmlPlistParser{r, xml.NewDecoder(r), strings.NewReplacer("\t", "", "\n", "", " ", "", "\r", ""), 0}
306 | }
307 |
--------------------------------------------------------------------------------
/vendor/src/github.com/DHowett/go-plist/xml_test.go:
--------------------------------------------------------------------------------
1 | package plist
2 |
3 | import (
4 | "bytes"
5 | "io/ioutil"
6 | "testing"
7 | )
8 |
9 | func BenchmarkXMLGenerate(b *testing.B) {
10 | for i := 0; i < b.N; i++ {
11 | d := newXMLPlistGenerator(ioutil.Discard)
12 | d.generateDocument(plistValueTree)
13 | }
14 | }
15 |
16 | func BenchmarkXMLParse(b *testing.B) {
17 | buf := bytes.NewReader([]byte(plistValueTreeAsXML))
18 | b.ResetTimer()
19 | for i := 0; i < b.N; i++ {
20 | b.StartTimer()
21 | d := newXMLPlistParser(buf)
22 | d.parseDocument()
23 | b.StopTimer()
24 | buf.Seek(0, 0)
25 | }
26 | }
27 |
28 | func TestVariousIllegalXMLPlists(t *testing.T) {
29 | plists := []string{
30 | "helo",
31 | "helo",
32 | "helo",
33 | "helo",
34 | "helo",
35 | "*@&%#helo",
36 | "*@&%#helo",
37 | "*@&%#helo",
38 | "10",
39 | "10",
40 | "10",
41 | "10",
42 | "10",
43 | "",
44 | "",
45 | "",
46 | "",
47 | " index {
151 | return &Json{a[index]}
152 | }
153 | }
154 | return &Json{nil}
155 | }
156 |
157 | // CheckGet returns a pointer to a new `Json` object and
158 | // a `bool` identifying success or failure
159 | //
160 | // useful for chained operations when success is important:
161 | // if data, ok := js.Get("top_level").CheckGet("inner"); ok {
162 | // log.Println(data)
163 | // }
164 | func (j *Json) CheckGet(key string) (*Json, bool) {
165 | m, err := j.Map()
166 | if err == nil {
167 | if val, ok := m[key]; ok {
168 | return &Json{val}, true
169 | }
170 | }
171 | return nil, false
172 | }
173 |
174 | // Map type asserts to `map`
175 | func (j *Json) Map() (map[string]interface{}, error) {
176 | if m, ok := (j.data).(map[string]interface{}); ok {
177 | return m, nil
178 | }
179 | return nil, errors.New("type assertion to map[string]interface{} failed")
180 | }
181 |
182 | // Array type asserts to an `array`
183 | func (j *Json) Array() ([]interface{}, error) {
184 | if a, ok := (j.data).([]interface{}); ok {
185 | return a, nil
186 | }
187 | return nil, errors.New("type assertion to []interface{} failed")
188 | }
189 |
190 | // Bool type asserts to `bool`
191 | func (j *Json) Bool() (bool, error) {
192 | if s, ok := (j.data).(bool); ok {
193 | return s, nil
194 | }
195 | return false, errors.New("type assertion to bool failed")
196 | }
197 |
198 | // String type asserts to `string`
199 | func (j *Json) String() (string, error) {
200 | if s, ok := (j.data).(string); ok {
201 | return s, nil
202 | }
203 | return "", errors.New("type assertion to string failed")
204 | }
205 |
206 | // Bytes type asserts to `[]byte`
207 | func (j *Json) Bytes() ([]byte, error) {
208 | if s, ok := (j.data).(string); ok {
209 | return []byte(s), nil
210 | }
211 | return nil, errors.New("type assertion to []byte failed")
212 | }
213 |
214 | // StringArray type asserts to an `array` of `string`
215 | func (j *Json) StringArray() ([]string, error) {
216 | arr, err := j.Array()
217 | if err != nil {
218 | return nil, err
219 | }
220 | retArr := make([]string, 0, len(arr))
221 | for _, a := range arr {
222 | if a == nil {
223 | retArr = append(retArr, "")
224 | continue
225 | }
226 | s, ok := a.(string)
227 | if !ok {
228 | return nil, err
229 | }
230 | retArr = append(retArr, s)
231 | }
232 | return retArr, nil
233 | }
234 |
235 | // MustArray guarantees the return of a `[]interface{}` (with optional default)
236 | //
237 | // useful when you want to interate over array values in a succinct manner:
238 | // for i, v := range js.Get("results").MustArray() {
239 | // fmt.Println(i, v)
240 | // }
241 | func (j *Json) MustArray(args ...[]interface{}) []interface{} {
242 | var def []interface{}
243 |
244 | switch len(args) {
245 | case 0:
246 | case 1:
247 | def = args[0]
248 | default:
249 | log.Panicf("MustArray() received too many arguments %d", len(args))
250 | }
251 |
252 | a, err := j.Array()
253 | if err == nil {
254 | return a
255 | }
256 |
257 | return def
258 | }
259 |
260 | // MustMap guarantees the return of a `map[string]interface{}` (with optional default)
261 | //
262 | // useful when you want to interate over map values in a succinct manner:
263 | // for k, v := range js.Get("dictionary").MustMap() {
264 | // fmt.Println(k, v)
265 | // }
266 | func (j *Json) MustMap(args ...map[string]interface{}) map[string]interface{} {
267 | var def map[string]interface{}
268 |
269 | switch len(args) {
270 | case 0:
271 | case 1:
272 | def = args[0]
273 | default:
274 | log.Panicf("MustMap() received too many arguments %d", len(args))
275 | }
276 |
277 | a, err := j.Map()
278 | if err == nil {
279 | return a
280 | }
281 |
282 | return def
283 | }
284 |
285 | // MustString guarantees the return of a `string` (with optional default)
286 | //
287 | // useful when you explicitly want a `string` in a single value return context:
288 | // myFunc(js.Get("param1").MustString(), js.Get("optional_param").MustString("my_default"))
289 | func (j *Json) MustString(args ...string) string {
290 | var def string
291 |
292 | switch len(args) {
293 | case 0:
294 | case 1:
295 | def = args[0]
296 | default:
297 | log.Panicf("MustString() received too many arguments %d", len(args))
298 | }
299 |
300 | s, err := j.String()
301 | if err == nil {
302 | return s
303 | }
304 |
305 | return def
306 | }
307 |
308 | // MustInt guarantees the return of an `int` (with optional default)
309 | //
310 | // useful when you explicitly want an `int` in a single value return context:
311 | // myFunc(js.Get("param1").MustInt(), js.Get("optional_param").MustInt(5150))
312 | func (j *Json) MustInt(args ...int) int {
313 | var def int
314 |
315 | switch len(args) {
316 | case 0:
317 | case 1:
318 | def = args[0]
319 | default:
320 | log.Panicf("MustInt() received too many arguments %d", len(args))
321 | }
322 |
323 | i, err := j.Int()
324 | if err == nil {
325 | return i
326 | }
327 |
328 | return def
329 | }
330 |
331 | // MustFloat64 guarantees the return of a `float64` (with optional default)
332 | //
333 | // useful when you explicitly want a `float64` in a single value return context:
334 | // myFunc(js.Get("param1").MustFloat64(), js.Get("optional_param").MustFloat64(5.150))
335 | func (j *Json) MustFloat64(args ...float64) float64 {
336 | var def float64
337 |
338 | switch len(args) {
339 | case 0:
340 | case 1:
341 | def = args[0]
342 | default:
343 | log.Panicf("MustFloat64() received too many arguments %d", len(args))
344 | }
345 |
346 | f, err := j.Float64()
347 | if err == nil {
348 | return f
349 | }
350 |
351 | return def
352 | }
353 |
354 | // MustBool guarantees the return of a `bool` (with optional default)
355 | //
356 | // useful when you explicitly want a `bool` in a single value return context:
357 | // myFunc(js.Get("param1").MustBool(), js.Get("optional_param").MustBool(true))
358 | func (j *Json) MustBool(args ...bool) bool {
359 | var def bool
360 |
361 | switch len(args) {
362 | case 0:
363 | case 1:
364 | def = args[0]
365 | default:
366 | log.Panicf("MustBool() received too many arguments %d", len(args))
367 | }
368 |
369 | b, err := j.Bool()
370 | if err == nil {
371 | return b
372 | }
373 |
374 | return def
375 | }
376 |
377 | // MustInt64 guarantees the return of an `int64` (with optional default)
378 | //
379 | // useful when you explicitly want an `int64` in a single value return context:
380 | // myFunc(js.Get("param1").MustInt64(), js.Get("optional_param").MustInt64(5150))
381 | func (j *Json) MustInt64(args ...int64) int64 {
382 | var def int64
383 |
384 | switch len(args) {
385 | case 0:
386 | case 1:
387 | def = args[0]
388 | default:
389 | log.Panicf("MustInt64() received too many arguments %d", len(args))
390 | }
391 |
392 | i, err := j.Int64()
393 | if err == nil {
394 | return i
395 | }
396 |
397 | return def
398 | }
399 |
400 | // MustUInt64 guarantees the return of an `uint64` (with optional default)
401 | //
402 | // useful when you explicitly want an `uint64` in a single value return context:
403 | // myFunc(js.Get("param1").MustUint64(), js.Get("optional_param").MustUint64(5150))
404 | func (j *Json) MustUint64(args ...uint64) uint64 {
405 | var def uint64
406 |
407 | switch len(args) {
408 | case 0:
409 | case 1:
410 | def = args[0]
411 | default:
412 | log.Panicf("MustUint64() received too many arguments %d", len(args))
413 | }
414 |
415 | i, err := j.Uint64()
416 | if err == nil {
417 | return i
418 | }
419 |
420 | return def
421 | }
422 |
--------------------------------------------------------------------------------
/vendor/src/github.com/bitly/go-simplejson/simplejson_go10.go:
--------------------------------------------------------------------------------
1 | // +build !go1.1
2 |
3 | package simplejson
4 |
5 | import (
6 | "encoding/json"
7 | "errors"
8 | "io"
9 | "reflect"
10 | )
11 |
12 | // NewFromReader returns a *Json by decoding from an io.Reader
13 | func NewFromReader(r io.Reader) (*Json, error) {
14 | j := new(Json)
15 | dec := json.NewDecoder(r)
16 | err := dec.Decode(&j.data)
17 | return j, err
18 | }
19 |
20 | // Implements the json.Unmarshaler interface.
21 | func (j *Json) UnmarshalJSON(p []byte) error {
22 | return json.Unmarshal(p, &j.data)
23 | }
24 |
25 | // Float64 coerces into a float64
26 | func (j *Json) Float64() (float64, error) {
27 | switch j.data.(type) {
28 | case float32, float64:
29 | return reflect.ValueOf(j.data).Float(), nil
30 | case int, int8, int16, int32, int64:
31 | return float64(reflect.ValueOf(j.data).Int()), nil
32 | case uint, uint8, uint16, uint32, uint64:
33 | return float64(reflect.ValueOf(j.data).Uint()), nil
34 | }
35 | return 0, errors.New("invalid value type")
36 | }
37 |
38 | // Int coerces into an int
39 | func (j *Json) Int() (int, error) {
40 | switch j.data.(type) {
41 | case float32, float64:
42 | return int(reflect.ValueOf(j.data).Float()), nil
43 | case int, int8, int16, int32, int64:
44 | return int(reflect.ValueOf(j.data).Int()), nil
45 | case uint, uint8, uint16, uint32, uint64:
46 | return int(reflect.ValueOf(j.data).Uint()), nil
47 | }
48 | return 0, errors.New("invalid value type")
49 | }
50 |
51 | // Int64 coerces into an int64
52 | func (j *Json) Int64() (int64, error) {
53 | switch j.data.(type) {
54 | case float32, float64:
55 | return int64(reflect.ValueOf(j.data).Float()), nil
56 | case int, int8, int16, int32, int64:
57 | return reflect.ValueOf(j.data).Int(), nil
58 | case uint, uint8, uint16, uint32, uint64:
59 | return int64(reflect.ValueOf(j.data).Uint()), nil
60 | }
61 | return 0, errors.New("invalid value type")
62 | }
63 |
64 | // Uint64 coerces into an uint64
65 | func (j *Json) Uint64() (uint64, error) {
66 | switch j.data.(type) {
67 | case float32, float64:
68 | return uint64(reflect.ValueOf(j.data).Float()), nil
69 | case int, int8, int16, int32, int64:
70 | return uint64(reflect.ValueOf(j.data).Int()), nil
71 | case uint, uint8, uint16, uint32, uint64:
72 | return reflect.ValueOf(j.data).Uint(), nil
73 | }
74 | return 0, errors.New("invalid value type")
75 | }
76 |
--------------------------------------------------------------------------------
/vendor/src/github.com/bitly/go-simplejson/simplejson_go10_test.go:
--------------------------------------------------------------------------------
1 | // +build !go1.1
2 |
3 | package simplejson
4 |
5 | import (
6 | "bytes"
7 | "github.com/bmizerany/assert"
8 | "strconv"
9 | "testing"
10 | )
11 |
12 | func TestNewFromReader(t *testing.T) {
13 | buf := bytes.NewBuffer([]byte(`{
14 | "test": {
15 | "array": [1, "2", 3],
16 | "arraywithsubs": [
17 | {"subkeyone": 1},
18 | {"subkeytwo": 2, "subkeythree": 3}
19 | ],
20 | "bignum": 8000000000
21 | }
22 | }`))
23 | js, err := NewFromReader(buf)
24 |
25 | //Standard Test Case
26 | assert.NotEqual(t, nil, js)
27 | assert.Equal(t, nil, err)
28 |
29 | arr, _ := js.Get("test").Get("array").Array()
30 | assert.NotEqual(t, nil, arr)
31 | for i, v := range arr {
32 | var iv int
33 | switch v.(type) {
34 | case float64:
35 | iv = int(v.(float64))
36 | case string:
37 | iv, _ = strconv.Atoi(v.(string))
38 | }
39 | assert.Equal(t, i+1, iv)
40 | }
41 |
42 | ma := js.Get("test").Get("array").MustArray()
43 | assert.Equal(t, ma, []interface{}{float64(1), "2", float64(3)})
44 |
45 | mm := js.Get("test").Get("arraywithsubs").GetIndex(0).MustMap()
46 | assert.Equal(t, mm, map[string]interface{}{"subkeyone": float64(1)})
47 |
48 | assert.Equal(t, js.Get("test").Get("bignum").MustInt64(), int64(8000000000))
49 | }
50 |
51 | func TestSimplejsonGo10(t *testing.T) {
52 | js, err := NewJson([]byte(`{
53 | "test": {
54 | "array": [1, "2", 3],
55 | "arraywithsubs": [
56 | {"subkeyone": 1},
57 | {"subkeytwo": 2, "subkeythree": 3}
58 | ],
59 | "bignum": 8000000000
60 | }
61 | }`))
62 |
63 | assert.NotEqual(t, nil, js)
64 | assert.Equal(t, nil, err)
65 |
66 | arr, _ := js.Get("test").Get("array").Array()
67 | assert.NotEqual(t, nil, arr)
68 | for i, v := range arr {
69 | var iv int
70 | switch v.(type) {
71 | case float64:
72 | iv = int(v.(float64))
73 | case string:
74 | iv, _ = strconv.Atoi(v.(string))
75 | }
76 | assert.Equal(t, i+1, iv)
77 | }
78 |
79 | ma := js.Get("test").Get("array").MustArray()
80 | assert.Equal(t, ma, []interface{}{float64(1), "2", float64(3)})
81 |
82 | mm := js.Get("test").Get("arraywithsubs").GetIndex(0).MustMap()
83 | assert.Equal(t, mm, map[string]interface{}{"subkeyone": float64(1)})
84 |
85 | assert.Equal(t, js.Get("test").Get("bignum").MustInt64(), int64(8000000000))
86 | }
87 |
--------------------------------------------------------------------------------
/vendor/src/github.com/bitly/go-simplejson/simplejson_go11.go:
--------------------------------------------------------------------------------
1 | // +build go1.1
2 |
3 | package simplejson
4 |
5 | import (
6 | "bytes"
7 | "encoding/json"
8 | "errors"
9 | "io"
10 | "reflect"
11 | "strconv"
12 | )
13 |
14 | // Implements the json.Unmarshaler interface.
15 | func (j *Json) UnmarshalJSON(p []byte) error {
16 | dec := json.NewDecoder(bytes.NewBuffer(p))
17 | dec.UseNumber()
18 | return dec.Decode(&j.data)
19 | }
20 |
21 | // NewFromReader returns a *Json by decoding from an io.Reader
22 | func NewFromReader(r io.Reader) (*Json, error) {
23 | j := new(Json)
24 | dec := json.NewDecoder(r)
25 | dec.UseNumber()
26 | err := dec.Decode(&j.data)
27 | return j, err
28 | }
29 |
30 | // Float64 coerces into a float64
31 | func (j *Json) Float64() (float64, error) {
32 | switch j.data.(type) {
33 | case json.Number:
34 | return j.data.(json.Number).Float64()
35 | case float32, float64:
36 | return reflect.ValueOf(j.data).Float(), nil
37 | case int, int8, int16, int32, int64:
38 | return float64(reflect.ValueOf(j.data).Int()), nil
39 | case uint, uint8, uint16, uint32, uint64:
40 | return float64(reflect.ValueOf(j.data).Uint()), nil
41 | }
42 | return 0, errors.New("invalid value type")
43 | }
44 |
45 | // Int coerces into an int
46 | func (j *Json) Int() (int, error) {
47 | switch j.data.(type) {
48 | case json.Number:
49 | i, err := j.data.(json.Number).Int64()
50 | return int(i), err
51 | case float32, float64:
52 | return int(reflect.ValueOf(j.data).Float()), nil
53 | case int, int8, int16, int32, int64:
54 | return int(reflect.ValueOf(j.data).Int()), nil
55 | case uint, uint8, uint16, uint32, uint64:
56 | return int(reflect.ValueOf(j.data).Uint()), nil
57 | }
58 | return 0, errors.New("invalid value type")
59 | }
60 |
61 | // Int64 coerces into an int64
62 | func (j *Json) Int64() (int64, error) {
63 | switch j.data.(type) {
64 | case json.Number:
65 | return j.data.(json.Number).Int64()
66 | case float32, float64:
67 | return int64(reflect.ValueOf(j.data).Float()), nil
68 | case int, int8, int16, int32, int64:
69 | return reflect.ValueOf(j.data).Int(), nil
70 | case uint, uint8, uint16, uint32, uint64:
71 | return int64(reflect.ValueOf(j.data).Uint()), nil
72 | }
73 | return 0, errors.New("invalid value type")
74 | }
75 |
76 | // Uint64 coerces into an uint64
77 | func (j *Json) Uint64() (uint64, error) {
78 | switch j.data.(type) {
79 | case json.Number:
80 | return strconv.ParseUint(j.data.(json.Number).String(), 10, 64)
81 | case float32, float64:
82 | return uint64(reflect.ValueOf(j.data).Float()), nil
83 | case int, int8, int16, int32, int64:
84 | return uint64(reflect.ValueOf(j.data).Int()), nil
85 | case uint, uint8, uint16, uint32, uint64:
86 | return reflect.ValueOf(j.data).Uint(), nil
87 | }
88 | return 0, errors.New("invalid value type")
89 | }
90 |
--------------------------------------------------------------------------------
/vendor/src/github.com/bitly/go-simplejson/simplejson_go11_test.go:
--------------------------------------------------------------------------------
1 | // +build go1.1
2 |
3 | package simplejson
4 |
5 | import (
6 | "bytes"
7 | "encoding/json"
8 | "github.com/bmizerany/assert"
9 | "strconv"
10 | "testing"
11 | )
12 |
13 | func TestNewFromReader(t *testing.T) {
14 | //Use New Constructor
15 | buf := bytes.NewBuffer([]byte(`{
16 | "test": {
17 | "array": [1, "2", 3],
18 | "arraywithsubs": [
19 | {"subkeyone": 1},
20 | {"subkeytwo": 2, "subkeythree": 3}
21 | ],
22 | "bignum": 9223372036854775807,
23 | "uint64": 18446744073709551615
24 | }
25 | }`))
26 | js, err := NewFromReader(buf)
27 |
28 | //Standard Test Case
29 | assert.NotEqual(t, nil, js)
30 | assert.Equal(t, nil, err)
31 |
32 | arr, _ := js.Get("test").Get("array").Array()
33 | assert.NotEqual(t, nil, arr)
34 | for i, v := range arr {
35 | var iv int
36 | switch v.(type) {
37 | case json.Number:
38 | i64, err := v.(json.Number).Int64()
39 | assert.Equal(t, nil, err)
40 | iv = int(i64)
41 | case string:
42 | iv, _ = strconv.Atoi(v.(string))
43 | }
44 | assert.Equal(t, i+1, iv)
45 | }
46 |
47 | ma := js.Get("test").Get("array").MustArray()
48 | assert.Equal(t, ma, []interface{}{json.Number("1"), "2", json.Number("3")})
49 |
50 | mm := js.Get("test").Get("arraywithsubs").GetIndex(0).MustMap()
51 | assert.Equal(t, mm, map[string]interface{}{"subkeyone": json.Number("1")})
52 |
53 | assert.Equal(t, js.Get("test").Get("bignum").MustInt64(), int64(9223372036854775807))
54 | assert.Equal(t, js.Get("test").Get("uint64").MustUint64(), uint64(18446744073709551615))
55 | }
56 |
57 | func TestSimplejsonGo11(t *testing.T) {
58 | js, err := NewJson([]byte(`{
59 | "test": {
60 | "array": [1, "2", 3],
61 | "arraywithsubs": [
62 | {"subkeyone": 1},
63 | {"subkeytwo": 2, "subkeythree": 3}
64 | ],
65 | "bignum": 9223372036854775807,
66 | "uint64": 18446744073709551615
67 | }
68 | }`))
69 |
70 | assert.NotEqual(t, nil, js)
71 | assert.Equal(t, nil, err)
72 |
73 | arr, _ := js.Get("test").Get("array").Array()
74 | assert.NotEqual(t, nil, arr)
75 | for i, v := range arr {
76 | var iv int
77 | switch v.(type) {
78 | case json.Number:
79 | i64, err := v.(json.Number).Int64()
80 | assert.Equal(t, nil, err)
81 | iv = int(i64)
82 | case string:
83 | iv, _ = strconv.Atoi(v.(string))
84 | }
85 | assert.Equal(t, i+1, iv)
86 | }
87 |
88 | ma := js.Get("test").Get("array").MustArray()
89 | assert.Equal(t, ma, []interface{}{json.Number("1"), "2", json.Number("3")})
90 |
91 | mm := js.Get("test").Get("arraywithsubs").GetIndex(0).MustMap()
92 | assert.Equal(t, mm, map[string]interface{}{"subkeyone": json.Number("1")})
93 |
94 | assert.Equal(t, js.Get("test").Get("bignum").MustInt64(), int64(9223372036854775807))
95 | assert.Equal(t, js.Get("test").Get("uint64").MustUint64(), uint64(18446744073709551615))
96 | }
97 |
--------------------------------------------------------------------------------
/vendor/src/github.com/bitly/go-simplejson/simplejson_test.go:
--------------------------------------------------------------------------------
1 | package simplejson
2 |
3 | import (
4 | "encoding/json"
5 | "testing"
6 |
7 | "github.com/bmizerany/assert"
8 | )
9 |
10 | func TestSimplejson(t *testing.T) {
11 | var ok bool
12 | var err error
13 |
14 | js, err := NewJson([]byte(`{
15 | "test": {
16 | "string_array": ["asdf", "ghjk", "zxcv"],
17 | "string_array_null": ["abc", null, "efg"],
18 | "array": [1, "2", 3],
19 | "arraywithsubs": [{"subkeyone": 1},
20 | {"subkeytwo": 2, "subkeythree": 3}],
21 | "int": 10,
22 | "float": 5.150,
23 | "string": "simplejson",
24 | "bool": true,
25 | "sub_obj": {"a": 1}
26 | }
27 | }`))
28 |
29 | assert.NotEqual(t, nil, js)
30 | assert.Equal(t, nil, err)
31 |
32 | _, ok = js.CheckGet("test")
33 | assert.Equal(t, true, ok)
34 |
35 | _, ok = js.CheckGet("missing_key")
36 | assert.Equal(t, false, ok)
37 |
38 | aws := js.Get("test").Get("arraywithsubs")
39 | assert.NotEqual(t, nil, aws)
40 | var awsval int
41 | awsval, _ = aws.GetIndex(0).Get("subkeyone").Int()
42 | assert.Equal(t, 1, awsval)
43 | awsval, _ = aws.GetIndex(1).Get("subkeytwo").Int()
44 | assert.Equal(t, 2, awsval)
45 | awsval, _ = aws.GetIndex(1).Get("subkeythree").Int()
46 | assert.Equal(t, 3, awsval)
47 |
48 | i, _ := js.Get("test").Get("int").Int()
49 | assert.Equal(t, 10, i)
50 |
51 | f, _ := js.Get("test").Get("float").Float64()
52 | assert.Equal(t, 5.150, f)
53 |
54 | s, _ := js.Get("test").Get("string").String()
55 | assert.Equal(t, "simplejson", s)
56 |
57 | b, _ := js.Get("test").Get("bool").Bool()
58 | assert.Equal(t, true, b)
59 |
60 | mi := js.Get("test").Get("int").MustInt()
61 | assert.Equal(t, 10, mi)
62 |
63 | mi2 := js.Get("test").Get("missing_int").MustInt(5150)
64 | assert.Equal(t, 5150, mi2)
65 |
66 | ms := js.Get("test").Get("string").MustString()
67 | assert.Equal(t, "simplejson", ms)
68 |
69 | ms2 := js.Get("test").Get("missing_string").MustString("fyea")
70 | assert.Equal(t, "fyea", ms2)
71 |
72 | ma2 := js.Get("test").Get("missing_array").MustArray([]interface{}{"1", 2, "3"})
73 | assert.Equal(t, ma2, []interface{}{"1", 2, "3"})
74 |
75 | mm2 := js.Get("test").Get("missing_map").MustMap(map[string]interface{}{"found": false})
76 | assert.Equal(t, mm2, map[string]interface{}{"found": false})
77 |
78 | strs, err := js.Get("test").Get("string_array").StringArray()
79 | assert.Equal(t, err, nil)
80 | assert.Equal(t, strs[0], "asdf")
81 | assert.Equal(t, strs[1], "ghjk")
82 | assert.Equal(t, strs[2], "zxcv")
83 |
84 | strs2, err := js.Get("test").Get("string_array_null").StringArray()
85 | assert.Equal(t, err, nil)
86 | assert.Equal(t, strs2[0], "abc")
87 | assert.Equal(t, strs2[1], "")
88 | assert.Equal(t, strs2[2], "efg")
89 |
90 | gp, _ := js.GetPath("test", "string").String()
91 | assert.Equal(t, "simplejson", gp)
92 |
93 | gp2, _ := js.GetPath("test", "int").Int()
94 | assert.Equal(t, 10, gp2)
95 |
96 | assert.Equal(t, js.Get("test").Get("bool").MustBool(), true)
97 |
98 | js.Set("float2", 300.0)
99 | assert.Equal(t, js.Get("float2").MustFloat64(), 300.0)
100 |
101 | js.Set("test2", "setTest")
102 | assert.Equal(t, "setTest", js.Get("test2").MustString())
103 |
104 | js.Del("test2")
105 | assert.NotEqual(t, "setTest", js.Get("test2").MustString())
106 |
107 | js.Get("test").Get("sub_obj").Set("a", 2)
108 | assert.Equal(t, 2, js.Get("test").Get("sub_obj").Get("a").MustInt())
109 |
110 | js.GetPath("test", "sub_obj").Set("a", 3)
111 | assert.Equal(t, 3, js.GetPath("test", "sub_obj", "a").MustInt())
112 | }
113 |
114 | func TestStdlibInterfaces(t *testing.T) {
115 | val := new(struct {
116 | Name string `json:"name"`
117 | Params *Json `json:"params"`
118 | })
119 | val2 := new(struct {
120 | Name string `json:"name"`
121 | Params *Json `json:"params"`
122 | })
123 |
124 | raw := `{"name":"myobject","params":{"string":"simplejson"}}`
125 |
126 | assert.Equal(t, nil, json.Unmarshal([]byte(raw), val))
127 |
128 | assert.Equal(t, "myobject", val.Name)
129 | assert.NotEqual(t, nil, val.Params.data)
130 | s, _ := val.Params.Get("string").String()
131 | assert.Equal(t, "simplejson", s)
132 |
133 | p, err := json.Marshal(val)
134 | assert.Equal(t, nil, err)
135 | assert.Equal(t, nil, json.Unmarshal(p, val2))
136 | assert.Equal(t, val, val2) // stable
137 | }
138 |
139 | func TestSet(t *testing.T) {
140 | js, err := NewJson([]byte(`{}`))
141 | assert.Equal(t, nil, err)
142 |
143 | js.Set("baz", "bing")
144 |
145 | s, err := js.GetPath("baz").String()
146 | assert.Equal(t, nil, err)
147 | assert.Equal(t, "bing", s)
148 | }
149 |
150 | func TestReplace(t *testing.T) {
151 | js, err := NewJson([]byte(`{}`))
152 | assert.Equal(t, nil, err)
153 |
154 | err = js.UnmarshalJSON([]byte(`{"baz":"bing"}`))
155 | assert.Equal(t, nil, err)
156 |
157 | s, err := js.GetPath("baz").String()
158 | assert.Equal(t, nil, err)
159 | assert.Equal(t, "bing", s)
160 | }
161 |
162 | func TestSetPath(t *testing.T) {
163 | js, err := NewJson([]byte(`{}`))
164 | assert.Equal(t, nil, err)
165 |
166 | js.SetPath([]string{"foo", "bar"}, "baz")
167 |
168 | s, err := js.GetPath("foo", "bar").String()
169 | assert.Equal(t, nil, err)
170 | assert.Equal(t, "baz", s)
171 | }
172 |
173 | func TestSetPathNoPath(t *testing.T) {
174 | js, err := NewJson([]byte(`{"some":"data","some_number":1.0,"some_bool":false}`))
175 | assert.Equal(t, nil, err)
176 |
177 | f := js.GetPath("some_number").MustFloat64(99.0)
178 | assert.Equal(t, f, 1.0)
179 |
180 | js.SetPath([]string{}, map[string]interface{}{"foo": "bar"})
181 |
182 | s, err := js.GetPath("foo").String()
183 | assert.Equal(t, nil, err)
184 | assert.Equal(t, "bar", s)
185 |
186 | f = js.GetPath("some_number").MustFloat64(99.0)
187 | assert.Equal(t, f, 99.0)
188 | }
189 |
190 | func TestPathWillAugmentExisting(t *testing.T) {
191 | js, err := NewJson([]byte(`{"this":{"a":"aa","b":"bb","c":"cc"}}`))
192 | assert.Equal(t, nil, err)
193 |
194 | js.SetPath([]string{"this", "d"}, "dd")
195 |
196 | cases := []struct {
197 | path []string
198 | outcome string
199 | }{
200 | {
201 | path: []string{"this", "a"},
202 | outcome: "aa",
203 | },
204 | {
205 | path: []string{"this", "b"},
206 | outcome: "bb",
207 | },
208 | {
209 | path: []string{"this", "c"},
210 | outcome: "cc",
211 | },
212 | {
213 | path: []string{"this", "d"},
214 | outcome: "dd",
215 | },
216 | }
217 |
218 | for _, tc := range cases {
219 | s, err := js.GetPath(tc.path...).String()
220 | assert.Equal(t, nil, err)
221 | assert.Equal(t, tc.outcome, s)
222 | }
223 | }
224 |
225 | func TestPathWillOverwriteExisting(t *testing.T) {
226 | // notice how "a" is 0.1 - but then we'll try to set at path a, foo
227 | js, err := NewJson([]byte(`{"this":{"a":0.1,"b":"bb","c":"cc"}}`))
228 | assert.Equal(t, nil, err)
229 |
230 | js.SetPath([]string{"this", "a", "foo"}, "bar")
231 |
232 | s, err := js.GetPath("this", "a", "foo").String()
233 | assert.Equal(t, nil, err)
234 | assert.Equal(t, "bar", s)
235 | }
236 |
--------------------------------------------------------------------------------
/vendor/src/github.com/codegangsta/inject/.gitignore:
--------------------------------------------------------------------------------
1 | inject
2 | inject.test
3 |
--------------------------------------------------------------------------------
/vendor/src/github.com/codegangsta/inject/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013 Jeremy Saenz
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/vendor/src/github.com/codegangsta/inject/README.md:
--------------------------------------------------------------------------------
1 | inject
2 | ======
3 |
4 | Dependency injection for go
5 |
--------------------------------------------------------------------------------
/vendor/src/github.com/codegangsta/inject/inject.go:
--------------------------------------------------------------------------------
1 | package inject
2 |
3 | import (
4 | "fmt"
5 | "reflect"
6 | )
7 |
8 | type Injector interface {
9 | Applicator
10 | Invoker
11 | TypeMapper
12 | SetParent(Injector)
13 | }
14 |
15 | type Applicator interface {
16 | Apply(interface{}) error
17 | }
18 |
19 | type Invoker interface {
20 | Invoke(interface{}) ([]reflect.Value, error)
21 | }
22 |
23 | type TypeMapper interface {
24 | Map(interface{}) TypeMapper
25 | MapTo(interface{}, interface{}) TypeMapper
26 | Get(reflect.Type) reflect.Value
27 | }
28 |
29 | type injector struct {
30 | values map[reflect.Type]reflect.Value
31 | parent Injector
32 | }
33 |
34 | func InterfaceOf(value interface{}) reflect.Type {
35 | t := reflect.TypeOf(value)
36 |
37 | for t.Kind() == reflect.Ptr {
38 | t = t.Elem()
39 | }
40 |
41 | if t.Kind() != reflect.Interface {
42 | panic("Called inject.InterfaceOf with a value that is not a pointer to an interface. (*MyInterface)(nil)")
43 | }
44 |
45 | return t
46 | }
47 |
48 | func New() Injector {
49 | return &injector{
50 | values: make(map[reflect.Type]reflect.Value),
51 | }
52 | }
53 |
54 | func (inj *injector) Invoke(f interface{}) ([]reflect.Value, error) {
55 | t := reflect.TypeOf(f)
56 |
57 | var in = make([]reflect.Value, t.NumIn())
58 | for i := 0; i < t.NumIn(); i++ {
59 | argType := t.In(i)
60 | val := inj.Get(argType)
61 | if !val.IsValid() {
62 | return nil, fmt.Errorf("Value not found for type %v", argType)
63 | }
64 |
65 | in[i] = val
66 | }
67 |
68 | return reflect.ValueOf(f).Call(in), nil
69 | }
70 |
71 | func (inj *injector) Apply(val interface{}) error {
72 | v := reflect.ValueOf(val)
73 |
74 | for v.Kind() == reflect.Ptr {
75 | v = v.Elem()
76 | }
77 |
78 | if v.Kind() != reflect.Struct {
79 | return nil
80 | }
81 |
82 | t := v.Type()
83 |
84 | for i := 0; i < v.NumField(); i++ {
85 | f := v.Field(i)
86 | structField := t.Field(i)
87 | if f.CanSet() && structField.Tag == "inject" {
88 | ft := f.Type()
89 | v := inj.Get(ft)
90 | if !v.IsValid() {
91 | return fmt.Errorf("Value not found for type %v", ft)
92 | }
93 |
94 | f.Set(v)
95 | }
96 |
97 | }
98 |
99 | return nil
100 | }
101 |
102 | func (i *injector) Map(val interface{}) TypeMapper {
103 | i.values[reflect.TypeOf(val)] = reflect.ValueOf(val)
104 | return i
105 | }
106 |
107 | func (i *injector) MapTo(val interface{}, ifacePtr interface{}) TypeMapper {
108 | i.values[InterfaceOf(ifacePtr)] = reflect.ValueOf(val)
109 | return i
110 | }
111 |
112 | func (i *injector) Get(t reflect.Type) reflect.Value {
113 | val := i.values[t]
114 | if !val.IsValid() && i.parent != nil {
115 | val = i.parent.Get(t)
116 | }
117 | return val
118 | }
119 |
120 | func (i *injector) SetParent(parent Injector) {
121 | i.parent = parent
122 | }
123 |
--------------------------------------------------------------------------------
/vendor/src/github.com/codegangsta/inject/inject_test.go:
--------------------------------------------------------------------------------
1 | package inject_test
2 |
3 | import (
4 | "github.com/codegangsta/inject"
5 | "reflect"
6 | "testing"
7 | )
8 |
9 | type SpecialString interface {
10 | }
11 |
12 | type TestStruct struct {
13 | Dep1 string `inject`
14 | Dep2 SpecialString `inject`
15 | Dep3 string
16 | }
17 |
18 | /* Test Helpers */
19 | func expect(t *testing.T, a interface{}, b interface{}) {
20 | if a != b {
21 | t.Errorf("Expected %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
22 | }
23 | }
24 |
25 | func refute(t *testing.T, a interface{}, b interface{}) {
26 | if a == b {
27 | t.Errorf("Did not expect %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
28 | }
29 | }
30 |
31 | func Test_InjectorInvoke(t *testing.T) {
32 | injector := inject.New()
33 | expect(t, injector == nil, false)
34 |
35 | dep := "some dependency"
36 | injector.Map(dep)
37 | dep2 := "another dep"
38 | injector.MapTo(dep2, (*SpecialString)(nil))
39 |
40 | _, err := injector.Invoke(func(d1 string, d2 SpecialString) {
41 | expect(t, d1, dep)
42 | expect(t, d2, dep2)
43 | })
44 |
45 | expect(t, err, nil)
46 | }
47 |
48 | func Test_InjectorInvokeReturnValues(t *testing.T) {
49 | injector := inject.New()
50 | expect(t, injector == nil, false)
51 |
52 | dep := "some dependency"
53 | injector.Map(dep)
54 | dep2 := "another dep"
55 | injector.MapTo(dep2, (*SpecialString)(nil))
56 |
57 | result, err := injector.Invoke(func(d1 string, d2 SpecialString) string {
58 | expect(t, d1, dep)
59 | expect(t, d2, dep2)
60 | return "Hello world"
61 | })
62 |
63 | expect(t, result[0].String(), "Hello world")
64 | expect(t, err, nil)
65 | }
66 |
67 | func Test_InjectorApply(t *testing.T) {
68 | injector := inject.New()
69 |
70 | injector.Map("a dep").MapTo("another dep", (*SpecialString)(nil))
71 |
72 | s := TestStruct{}
73 | err := injector.Apply(&s)
74 | expect(t, err, nil)
75 |
76 | expect(t, s.Dep1, "a dep")
77 | expect(t, s.Dep2, "another dep")
78 | }
79 |
80 | func Test_InterfaceOf(t *testing.T) {
81 | iType := inject.InterfaceOf((*SpecialString)(nil))
82 | expect(t, iType.Kind(), reflect.Interface)
83 |
84 | iType = inject.InterfaceOf((**SpecialString)(nil))
85 | expect(t, iType.Kind(), reflect.Interface)
86 |
87 | // Expecting nil
88 | defer func() {
89 | rec := recover()
90 | refute(t, rec, nil)
91 | }()
92 | iType = inject.InterfaceOf((*testing.T)(nil))
93 | }
94 |
95 | func Test_InjectorGet(t *testing.T) {
96 | injector := inject.New()
97 |
98 | injector.Map("some dependency")
99 |
100 | expect(t, injector.Get(reflect.TypeOf("string")).IsValid(), true)
101 | expect(t, injector.Get(reflect.TypeOf(11)).IsValid(), false)
102 | }
103 |
104 | func Test_InjectorSetParent(t *testing.T) {
105 | injector := inject.New()
106 | injector.MapTo("another dep", (*SpecialString)(nil))
107 |
108 | injector2 := inject.New()
109 | injector2.SetParent(injector)
110 |
111 | expect(t, injector2.Get(inject.InterfaceOf((*SpecialString)(nil))).IsValid(), true)
112 | }
113 |
--------------------------------------------------------------------------------
/vendor/src/github.com/nbjahan/go-launchbar/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2014 go-launchbar by nbjahan - https://github.com/nbjahan/go-launchbar
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
20 |
--------------------------------------------------------------------------------
/vendor/src/github.com/nbjahan/go-launchbar/README.md:
--------------------------------------------------------------------------------
1 | [LaunchBar v6](http://obdev.at/products/launchbar) helper for golang
2 |
3 | Use this to quickly write LaunchBar v6 actions like a pro
4 |
5 | The API has not been frozen yet.
6 |
7 | Check these repos to see how to use this:
8 |
9 | https://github.com/nbjahan/launchbar-pinboard
10 | https://github.com/nbjahan/launchbar-spotlight
11 |
12 | Docs:
13 |
14 | http://godoc.org/github.com/nbjahan/go-launchbar
15 |
--------------------------------------------------------------------------------
/vendor/src/github.com/nbjahan/go-launchbar/cache.go:
--------------------------------------------------------------------------------
1 | package launchbar
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "io/ioutil"
7 | "log"
8 | "os"
9 | "path"
10 | "path/filepath"
11 | "time"
12 | )
13 |
14 | type CacheError string
15 |
16 | func (c CacheError) Error() string {
17 | return string(c)
18 | }
19 |
20 | var (
21 | ErrCacheDoesNotExists = CacheError("the cache does not exists")
22 | ErrCacheIsCorrupted = CacheError("the cache is corrupted")
23 | ErrCacheIsExpired = CacheError("the cache is expired")
24 | )
25 |
26 | // Cache provides tools for non permanent storage
27 | type Cache struct {
28 | path string
29 | }
30 |
31 | // NewCache initialize and returns a new Cache
32 | func NewCache(p string) *Cache {
33 | return &Cache{path: p}
34 | }
35 |
36 | type cacheItem struct {
37 | Time *time.Time `json:"expiry"`
38 | Items []*item `json:"items"`
39 | }
40 | type genericCache struct {
41 | Time *time.Time `json:"expiry"`
42 | Data interface{} `json:"data"`
43 | }
44 |
45 | // Delete removes a cachefile for the specified key
46 | func (c *Cache) Delete(key string) {
47 | if !path.IsAbs(c.path) || path.Dir(c.path) != os.ExpandEnv("$HOME/Library/Caches/at.obdev.LaunchBar/Actions") {
48 | panic(fmt.Sprintf("bad cache path: %q", c.path))
49 | }
50 | p := path.Join(c.path, key)
51 | if stat, err := os.Stat(p); err == nil {
52 | if !stat.IsDir() {
53 | if filepath.Dir(p) == c.path {
54 | os.Remove(p)
55 | }
56 | }
57 | }
58 | }
59 |
60 | // Set stores the data in a file identified by the key and with the lifetime of d
61 | func (c *Cache) Set(key string, data interface{}, d time.Duration) {
62 | wd, err := os.Create(path.Join(c.path, key))
63 | if err != nil {
64 | log.Fatalln(err)
65 | }
66 | defer wd.Close()
67 | t := time.Now().Add(d)
68 | b, err := json.Marshal(genericCache{&t, data})
69 | if err != nil {
70 | log.Fatalln(err)
71 | }
72 | wd.Write(b)
73 | }
74 |
75 | // Get the data from cachefile specified by the key and stores it into the value pointed to by v
76 | //
77 | // if the cache does not exists it returns nil, ErrCacheDoesNotExists
78 | //
79 | // if the cache is expired it returns the expire time and ErrCacheIsExpired
80 | //
81 | // if there's an error reading the cachefile it returns nil, ErrCacheIsCorrupted
82 | //
83 | // Otherwise it returns the expiry time, nil
84 | func (c *Cache) Get(key string, v interface{}) (*time.Time, error) {
85 | if _, err := os.Stat(path.Join(c.path, key)); err != nil {
86 | return nil, ErrCacheDoesNotExists
87 | }
88 | rd, err := os.Open(path.Join(c.path, key))
89 | if err != nil {
90 | log.Fatalln(err)
91 | }
92 | data, err := ioutil.ReadAll(rd)
93 | if err != nil {
94 | return nil, ErrCacheIsCorrupted
95 | }
96 |
97 | var e genericCache
98 | e.Data = &v
99 | // e := cacheItem{Items: &Items}
100 | // err = gob.NewDecoder(rd).Decode(&e)
101 | err = json.Unmarshal(data, &e)
102 | if err != nil {
103 | return nil, ErrCacheIsCorrupted
104 | }
105 | if time.Now().After(*e.Time) {
106 | return e.Time, ErrCacheIsExpired
107 | }
108 | return e.Time, nil
109 | }
110 |
111 | // SetItems is a helper function to store some Items
112 | func (c *Cache) SetItems(key string, items *Items, d time.Duration) {
113 | wd, err := os.Create(path.Join(c.path, key))
114 | if err != nil {
115 | log.Fatalln(err)
116 | }
117 | defer wd.Close()
118 | t := time.Now().Add(d)
119 | // err = gob.NewEncoder(wd).Encode([]interface{}{t.Unix(), e})
120 | b, err := json.Marshal(cacheItem{&t, items.getItems()})
121 | if err != nil {
122 | log.Fatalln(err)
123 | }
124 | wd.Write(b)
125 | }
126 |
127 | // GetItemsWithInfo is a helper function to get the stored items from the caceh
128 | // with the expiry time and error
129 | func (c *Cache) GetItemsWithInfo(key string) (*Items, *time.Time, error) {
130 | if _, err := os.Stat(path.Join(c.path, key)); err != nil {
131 | return nil, nil, ErrCacheDoesNotExists
132 | }
133 | rd, err := os.Open(path.Join(c.path, key))
134 | if err != nil {
135 | log.Fatalln(err)
136 | }
137 | data, err := ioutil.ReadAll(rd)
138 | if err != nil {
139 | return nil, nil, ErrCacheIsCorrupted
140 | }
141 |
142 | var e cacheItem
143 | // e := cacheItem{Items: &Items}
144 | // err = gob.NewDecoder(rd).Decode(&e)
145 | err = json.Unmarshal(data, &e)
146 | if err != nil {
147 | return nil, nil, ErrCacheIsCorrupted
148 | }
149 | items := &Items{}
150 | items.setItems(e.Items)
151 |
152 | if time.Now().After(*e.Time) {
153 | return items, e.Time, ErrCacheIsExpired
154 | }
155 | return items, e.Time, nil
156 |
157 | }
158 |
159 | // GetItems is a helper function to get the stored items from the cache
160 | func (c *Cache) GetItems(key string) *Items {
161 | items, _, _ := c.GetItemsWithInfo(key)
162 | return items
163 | }
164 |
--------------------------------------------------------------------------------
/vendor/src/github.com/nbjahan/go-launchbar/config.go:
--------------------------------------------------------------------------------
1 | package launchbar
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "io/ioutil"
7 | "os"
8 | "path"
9 |
10 | "time"
11 | )
12 |
13 | // ConfigValues represents a Config values
14 | type ConfigValues map[string]interface{}
15 |
16 | // Config provides permanent config utils for the action.
17 | type Config struct {
18 | path string
19 | data map[string]interface{}
20 | }
21 |
22 | // NewConfig initializes an new Config object with the specified path and returns it.
23 | func NewConfig(p string) *Config {
24 | return loadConfig(p)
25 | }
26 |
27 | // NewConfigDefaults initializes a new Config object with the specified path
28 | // and default values and returns it.
29 | func NewConfigDefaults(p string, defaults ConfigValues) *Config {
30 | config := loadConfig(p)
31 | for k, v := range defaults {
32 | if _, found := config.data[k]; !found {
33 | config.data[k] = v
34 | }
35 | }
36 | config.save()
37 | return config
38 | }
39 |
40 | // Delete removes the key from config file.
41 | func (c *Config) Delete(keys ...string) {
42 | for _, key := range keys {
43 | delete(c.data, key)
44 | }
45 | c.save()
46 | }
47 |
48 | // Set sets the key, val and saves the config to the disk.
49 | func (c *Config) Set(key string, val interface{}) {
50 | if !path.IsAbs(c.path) || path.Dir(path.Dir(c.path)) != os.ExpandEnv("$HOME/Library/Application Support/LaunchBar/Action Support") {
51 | panic(fmt.Sprintf("bad config path: %q", c.path))
52 | }
53 |
54 | c.data[key] = val
55 | c.save()
56 | }
57 |
58 | // Get gets the value from config for the key
59 | func (c *Config) Get(key string) interface{} {
60 | return c.data[key]
61 | }
62 |
63 | // GetString gets the value from config for the key as string
64 | func (c *Config) GetString(key string) string {
65 | if c.data[key] == nil {
66 | return ""
67 | }
68 | return fmt.Sprintf("%v", c.data[key])
69 | }
70 |
71 | // GetInt gets the value from config for the key as int64
72 | func (c *Config) GetInt(key string) int64 {
73 | if c.data[key] == nil {
74 | return 0
75 | }
76 | i, ok := c.data[key].(float64)
77 | if !ok {
78 | return 0
79 | }
80 | return int64(i)
81 | }
82 |
83 | // GetFloat gets the value from config for the key as float64
84 | func (c *Config) GetFloat(key string) float64 {
85 | if c.data[key] == nil {
86 | return 0
87 | }
88 |
89 | i, ok := c.data[key].(float64)
90 | if !ok {
91 | return 0
92 | }
93 | return i
94 | }
95 |
96 | // GetBool gets the value from config for the key as bool
97 | func (c *Config) GetBool(key string) bool {
98 | if c.data[key] == nil {
99 | return false
100 | }
101 |
102 | b, ok := c.data[key].(bool)
103 | if !ok {
104 | return false
105 | }
106 | return b
107 | }
108 |
109 | // GetTimeDuration gets the value from config for the key as time.Duration
110 | func (c *Config) GetTimeDuration(key string) time.Duration {
111 | if c.data[key] == nil {
112 | return time.Duration(0)
113 | }
114 |
115 | d, ok := c.data[key].(float64)
116 | if !ok {
117 | return 0
118 | }
119 | return time.Duration(d)
120 | }
121 |
122 | func loadConfig(p string) *Config {
123 | p = path.Join(p, "config.json")
124 | config := &Config{path: p, data: make(ConfigValues)}
125 |
126 | if data, err := ioutil.ReadFile(p); err == nil {
127 | json.Unmarshal(data, &config.data)
128 | }
129 | return config
130 | }
131 |
132 | func (c *Config) save() {
133 | if data, err := json.Marshal(&c.data); err == nil {
134 | ioutil.WriteFile(c.path, data, 0664)
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/vendor/src/github.com/nbjahan/go-launchbar/context.go:
--------------------------------------------------------------------------------
1 | package launchbar
2 |
3 | import "log"
4 |
5 | // Context is a dependency that is available in Matcher, Runner, Renderer func
6 | type Context struct {
7 | Action *Action // points to the LaunchBar action
8 | Config *Config // the Config object
9 | Cache *Cache // the Cache object
10 | Self *Item // the item that is accessing the context
11 | Input *Input // the user input
12 | Logger *log.Logger // Logger is used to log to Action.SupportPath() + '/error.log'
13 | }
14 |
--------------------------------------------------------------------------------
/vendor/src/github.com/nbjahan/go-launchbar/input.go:
--------------------------------------------------------------------------------
1 | package launchbar
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "os"
7 | "strconv"
8 | "strings"
9 | )
10 |
11 | // Input represents the object that LaunchBar passes to scripts
12 | type Input struct {
13 | Item *Item
14 |
15 | args []string
16 | isObject bool
17 | isString bool
18 | isPaths bool
19 | isNumber bool
20 | isFloat bool
21 | isInt bool
22 | isLiveFeedback bool
23 | hasFunc bool
24 | hasData bool
25 | paths []string
26 | number float64
27 | }
28 |
29 | func exists(p string) bool {
30 | _, err := os.Stat(p)
31 | return err == nil
32 | }
33 |
34 | func NewInput(a *Action, args []string) *Input {
35 | item := item{}
36 | var in = &Input{
37 | args: args,
38 | }
39 |
40 | if len(args) == 0 {
41 | return in
42 | }
43 |
44 | in.isLiveFeedback = a.IsBackground()
45 | if len(args) > 1 {
46 | in.isPaths = true
47 | in.paths = args
48 | return in
49 | }
50 |
51 | if len(args) == 1 && exists(args[0]) {
52 | in.isPaths = true
53 | in.paths = args
54 | return in
55 | }
56 |
57 | if err := json.Unmarshal([]byte(args[0]), &item); err == nil {
58 | in.isObject = true
59 | if item.Data != nil && len(item.Data) > 0 {
60 | in.hasData = true
61 | }
62 | in.Item = a.GetItem(item.ID)
63 | if in.Item == nil {
64 | in.Item = newItem(&item)
65 | }
66 | in.Item.item.Arg = item.Arg
67 |
68 | in.Item.item.Order = item.Order
69 | in.Item.item.FuncName = item.FuncName
70 | in.Item.item.Data = item.Data
71 | if item.FuncName != "" {
72 | in.hasFunc = true
73 | }
74 | if in.Item.item.Path != "" && exists(in.Item.item.Path) {
75 | in.isPaths = true
76 | in.paths = []string{in.Item.item.Path}
77 | }
78 | } else {
79 | in.isString = true
80 | if f64, err := strconv.ParseFloat(in.String(), 64); err == nil {
81 | in.isNumber = true
82 | in.number = f64
83 | if fmt.Sprintf("%f", f64) == fmt.Sprintf("%f", float64(int64(f64))) {
84 | in.isInt = true
85 | } else {
86 | in.isFloat = true
87 | }
88 | }
89 | }
90 | return in
91 |
92 | }
93 |
94 | func (in *Input) Int() int { return int(in.number) }
95 | func (in *Input) Float64() float64 { return in.number }
96 | func (in *Input) Int64() int64 { return int64(in.number) }
97 | func (in *Input) Raw() string { return strings.Join(in.args, "\n") }
98 |
99 | func (in *Input) String() string {
100 | if in.IsObject() {
101 | return in.Item.item.Arg
102 | }
103 | return in.Raw()
104 | }
105 |
106 | func (in *Input) FuncArg() string {
107 | if out := in.FuncArgs(); len(out) > 0 {
108 | return out[0]
109 | }
110 | return ""
111 | }
112 |
113 | // TODO:
114 | // Deprecated use FuncArgs
115 | func (in *Input) FuncArgsString() []string {
116 | out := in.FuncArgs()
117 | l := len(out)
118 | if l == 0 {
119 | return nil
120 | }
121 | args := make([]string, l)
122 | for i := 0; i < l; i++ {
123 | args[i] = out[i]
124 | }
125 | return args
126 | }
127 |
128 | // TODO:
129 | // Deprecated use FuncArgs
130 | func (in *Input) FuncArgsMapString() map[int]string { return in.FuncArgs() }
131 |
132 | func (in *Input) FuncArgs() map[int]string {
133 | out := make(map[int]string)
134 | if !in.isObject {
135 | return nil
136 | }
137 | var args []interface{}
138 | err := json.Unmarshal([]byte(in.Item.item.FuncArg), &args)
139 | if err != nil {
140 | out[0] = in.Item.item.FuncArg
141 | return out
142 | }
143 | for i, arg := range args {
144 | out[i] = fmt.Sprintf("%v", arg)
145 | }
146 | return out
147 | }
148 |
149 | func (in *Input) Title() string {
150 | if in.IsObject() {
151 | return in.Item.item.Title
152 | }
153 | return ""
154 | }
155 |
156 | func (in *Input) Data(key string) interface{} {
157 | if in.hasData {
158 | if i, ok := in.Item.item.Data[key]; ok {
159 | return i
160 | }
161 | }
162 | return nil
163 | }
164 |
165 | // DataString returns a customdata[key] as string
166 | func (in *Input) DataString(key string) string {
167 | if in.Item == nil {
168 | return ""
169 | }
170 | if s, ok := in.Item.item.Data[key].(string); ok {
171 | return s
172 | }
173 | return ""
174 | }
175 |
176 | // DataInt returns a customdata[key] as string
177 | func (in *Input) DataInt(key string) int {
178 | if s, ok := in.Item.item.Data[key].(int); ok {
179 | return s
180 | }
181 | return 0
182 | }
183 |
184 | func (in *Input) IsString() bool { return in.isString }
185 | func (in *Input) IsObject() bool { return in.isObject }
186 | func (in *Input) IsPaths() bool { return in.isPaths }
187 | func (in *Input) IsNumber() bool { return in.isNumber }
188 | func (in *Input) IsInt() bool { return in.isInt }
189 | func (in *Input) IsFloat() bool { return in.isFloat }
190 | func (in *Input) IsEmpty() bool { return in.String() == "" }
191 |
192 | // FIXME: experimental
193 | func (in *Input) IsLiveFeedback() bool { return in.isLiveFeedback }
194 |
195 | func (in *Input) Paths() []string { return in.paths }
196 |
--------------------------------------------------------------------------------
/vendor/src/github.com/nbjahan/go-launchbar/item.go:
--------------------------------------------------------------------------------
1 | package launchbar
2 |
3 | import "encoding/json"
4 |
5 | // Func represents a generic type to pass functions.
6 | type Func interface{}
7 |
8 | // FuncMap represents a predefined map of functions to execute with Item.Run
9 | type FuncMap map[string]Func
10 |
11 | // AlwaysMatch is a Matcher func that always returns true.
12 | var AlwasMatch = func() bool { return true }
13 |
14 | // NeverMatch is a Matcher func that always returns false.
15 | var NeverMatch = func() bool { return false }
16 |
17 | // MatchIfTrueFunc is Matcher func that returns true if a value of passed argument is true.
18 | var MatchIfTrueFunc = func(b bool) func() bool { return func() bool { return b } }
19 |
20 | // MatchIfFalseFunc is Matcher func that returns true a value of passes argument is false.
21 | var MatchIfFalseFunc = func(b bool) func() bool { return func() bool { return !b } }
22 |
23 | // ShowViewFunc is a Runner func that shows the specified view.
24 | var ShowViewFunc = func(v string) func(*Context) { return func(c *Context) { c.Action.ShowView(v) } }
25 |
26 | // Item represents the LaunchBar item
27 | type Item struct {
28 | View *View
29 | item *item
30 | match Func // Matcher func
31 | run Func // Runner func
32 | render Func // Renderer func
33 | children []item
34 | }
35 |
36 | // NewItem initialize and returns a new Item
37 | func NewItem(title string) *Item {
38 | return &Item{
39 | item: &item{
40 | Title: title,
41 | Data: make(map[string]interface{}),
42 | },
43 | }
44 | }
45 |
46 | func newItem(item *item) *Item {
47 | return &Item{item: item}
48 | }
49 |
50 | type item struct {
51 | // Standard fields
52 | Title string `json:"title,omitempty"`
53 | Subtitle string `json:"subtitle,omitempty"`
54 | URL string `json:"url,omitempty"`
55 | Path string `json:"path,omitempty"`
56 | Icon string `json:"icon,omitempty"`
57 | QuickLookURL string `json:"quickLookURL,omitempty"`
58 | Action string `json:"action,omitempty"`
59 | ActionArgument string `json:"actionArgument,omitempty"`
60 | ActionReturnsItems bool `json:"actionReturnsItems,omitempty"`
61 | ActionRunsInBackground bool `json:"actionRunsInBackground,omitempty"`
62 | ActionBundleIdentifier string `json:"actionBundleIdentifier,omitempty"`
63 | Children []*item `json:"children,omitempty"`
64 |
65 | // Custom fields
66 | ID int `json:"x-id,omitempty"`
67 | Order int `json:"x-order,omitempty"`
68 | FuncName string `json:"x-func,omitempty"`
69 | FuncArg string `json:"x-funcarg,omitempty"`
70 | Arg string `json:"x-arg,omitempty"`
71 | Data map[string]interface{} `json:"x-data,omitempty"`
72 | }
73 |
74 | // SetTitle sets the Item's title.
75 | func (i *Item) SetTitle(title string) *Item { i.item.Title = title; return i }
76 |
77 | // SetSubtitle sets the Item's subtitle that appears below or next to the title.
78 | func (i *Item) SetSubtitle(subtitle string) *Item { i.item.Subtitle = subtitle; return i }
79 |
80 | // SetURL sets the Item's URL. When the user selects the item and hits Enter, this URL is opened.
81 | func (i *Item) SetURL(url string) *Item { i.item.URL = url; return i }
82 |
83 | // SetPath sets the absolute path of a file or folder the item represents. If
84 | // icon is not set, LaunchBar automatically uses an item that represents the
85 | // path.
86 | func (i *Item) SetPath(path string) *Item { i.item.Path = path; return i }
87 |
88 | // SetIcon sets the icon for the item. This is a string that is interpreted
89 | // the same way as CFBundleIconFile in the action’s Info.plist.
90 | // http://www.obdev.at/resources/launchbar/developer-documentation/action-info-plist.html#info-plist-CFBundleIconFile
91 | func (i *Item) SetIcon(icon string) *Item { i.item.Icon = icon; return i }
92 |
93 | // SetQuickLookURL sets the URL to be shown by the QuickLook panel when the
94 | // user hits ⌘Y on the item. This can by any URL supported by QuickLook,
95 | // including http of file URLs. Items that have a path property automatically
96 | // support QuickLook and do not need to set this property too.
97 | func (i *Item) SetQuickLookURL(qlurl string) *Item { i.item.QuickLookURL = qlurl; return i }
98 |
99 | // SetAction sets the name of an action that should be run when the user
100 | // selects this item and hits Enter. This is the name of a script file
101 | // inside the action bundle’s Scripts folder, including the file name
102 | // extension.
103 | //
104 | // The argument for the action depends on the value of actionArgument.
105 | func (i *Item) SetAction(action string) *Item { i.item.Action = action; return i }
106 |
107 | // SetActionArgument sets the argument to pass to the action.
108 | //
109 | // When the user selects this item and hits Enter and the item has an action
110 | // set, this is the argument that gets passed to that action as a string. If
111 | // this key is not present, the whole item is passed as an argument as a JSON
112 | // string
113 | func (i *Item) SetActionArgument(arg string) *Item { i.item.ActionArgument = arg; return i }
114 |
115 | // SetActionBundleIdentifier sets the identifier of an action that should be
116 | // run when the user selects this item and hits enter
117 | func (i *Item) SetActionBundleIdentifier(s string) *Item { i.item.ActionBundleIdentifier = s; return i }
118 |
119 | // SetActionRunsInBackground sets the action to be run in background
120 | //
121 | // See
122 | // http://www.obdev.at/resources/launchbar/developer-documentation/action-info-plist.html#info-plist-LBRunInBackground
123 | // for more detail.
124 | func (i *Item) SetActionRunsInBackground(b bool) *Item { i.item.ActionRunsInBackground = b; return i }
125 |
126 | // SetActionReturnsItems specifies that selecting and executing the item (as
127 | // specified by the action key) will return a new list of items. If this is set
128 | // to true, the item will have a chevron on the right side indicating that the
129 | // user can navigate into it and doing so causes action to be executed.
130 | func (i *Item) SetActionReturnsItems(b bool) *Item { i.item.ActionReturnsItems = b; return i }
131 |
132 | // SetChildren sets an array of items.
133 | func (i *Item) SetChildren(items *Items) *Item { i.item.Children = items.getItems(); return i }
134 |
135 | // SetMatch sets the matcher func of this item. This func determines that if
136 | // the item should be visible or not.
137 | //
138 | // Example:
139 | // func(c *Context) bool { return c.Action.IsControlKey() }
140 | func (i *Item) SetMatch(fn Func) *Item { i.match = fn; return i }
141 |
142 | // SetRun sets the runner func of this item. This func is optional and will be
143 | // run when the user selects the item and hit Enter. Runner func output is
144 | // optional, if it returns Items those items will be displayed to the user.
145 | //
146 | // Example:
147 | // func(c *Context) { c.Action.ShowView("main") }
148 | func (i *Item) SetRun(fn Func) *Item { i.run = fn; return i }
149 |
150 | // SetRender sets the renderer func of this item. This func will be executed
151 | // each time the user enters a key and can be used to update the values based
152 | // on the user input.
153 | // Example:
154 | // func(c *Context) { c.Self.SetSubtitle("") }
155 | func (i *Item) SetRender(fn Func) *Item { i.render = fn; return i }
156 |
157 | // SetOrder sets the order of the item. The Items are ordered by their creation time.
158 | func (i *Item) SetOrder(n int) *Item { i.item.Order = n; return i }
159 |
160 | // Item returns an underlying LaunchBar item that can be passed around in json format.
161 | func (i *Item) Item() *item { return i.item }
162 |
163 | // Done returns the pointer to the Item's view, used for chaining the item creation.
164 | func (i *Item) Done() *View { return i.View }
165 |
166 | // Run sets the predefined func (see FuncMap) to be run with the optional
167 | // arguments when the user selects this item and hit Enter
168 | func (i *Item) Run(f string, args ...interface{}) *Item {
169 | i.item.FuncName = f
170 | var ok bool
171 | var s string
172 | if len(args) == 1 {
173 | if s, ok = args[0].(string); ok {
174 | i.item.FuncArg = s
175 | }
176 | }
177 | if len(args) > 1 || !ok {
178 | b, err := json.Marshal(args)
179 | if err == nil {
180 | i.item.FuncArg = string(b)
181 | }
182 | }
183 | return i
184 | }
185 |
--------------------------------------------------------------------------------
/vendor/src/github.com/nbjahan/go-launchbar/items.go:
--------------------------------------------------------------------------------
1 | package launchbar
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | )
7 |
8 | // Items represents the collection of items
9 | type Items []*Item
10 |
11 | // NewItems creates an empty Items collection
12 | func NewItems() *Items {
13 | return &Items{}
14 | }
15 |
16 | // Add adds passes Items to the collection and returns the collection.
17 | func (items *Items) Add(i ...*Item) *Items {
18 | for _, item := range i {
19 | *items = append(*items, item)
20 | }
21 | return items
22 | }
23 |
24 | func (i *Items) setItems(items []*item) {
25 | for _, item := range items {
26 | i.Add(newItem(item))
27 | }
28 | }
29 |
30 | func (items *Items) getItems() []*item {
31 | a := make([]*item, len(*items))
32 | for i, item := range *items {
33 | a[i] = item.item
34 | }
35 | return a
36 | }
37 |
38 | type itemsByOrder Items
39 |
40 | func (o itemsByOrder) Len() int { return len(o) }
41 | func (o itemsByOrder) Swap(i, j int) { o[i], o[j] = o[j], o[i] }
42 | func (o itemsByOrder) Less(i, j int) bool { return o[i].item.Order < o[j].item.Order }
43 |
44 | // Compile returns items collection as a json string.
45 | func (items *Items) Compile() string {
46 | if items == nil {
47 | return ""
48 | }
49 | if len(*items) == 0 {
50 | return ""
51 | }
52 |
53 | b, err := json.Marshal(items.getItems())
54 | if err != nil {
55 | return fmt.Sprintf(`[{"title": "%v","subtitle":"error"}]`, err)
56 | }
57 | return string(b)
58 | }
59 |
--------------------------------------------------------------------------------
/vendor/src/github.com/nbjahan/go-launchbar/launchbar.go:
--------------------------------------------------------------------------------
1 | // Package launchbar is a package to quickly write LaunchBar v6 actions like a pro
2 | //
3 | // For example check :
4 | // https://github.com/nbjahan/launchbar-pinboard
5 | // https://github.com/nbjahan/launchbar-spotlight
6 | package launchbar
7 |
8 | import (
9 | "fmt"
10 | "io/ioutil"
11 | "log"
12 | "os"
13 | "os/exec"
14 | "path"
15 | "strings"
16 | "time"
17 |
18 | "github.com/DHowett/go-plist"
19 | "github.com/bitly/go-simplejson"
20 | "github.com/codegangsta/inject"
21 | )
22 |
23 | type infoPlist map[string]interface{}
24 |
25 | // Action represents a LaunchBar action
26 | type Action struct {
27 | inject.Injector // Used for dependency injection
28 | Config *Config
29 | Cache *Cache
30 | Input *Input
31 | Logger *log.Logger
32 | name string
33 | views map[string]*View
34 | items []*Item
35 | context *Context
36 | funcs *FuncMap
37 | info infoPlist
38 | }
39 |
40 | // NewAction creates an empty action, ready to populate with views
41 | func NewAction(name string, config ConfigValues) *Action {
42 | a := &Action{
43 | Injector: inject.New(),
44 | name: name,
45 | views: make(map[string]*View),
46 | items: make([]*Item, 0),
47 | }
48 |
49 | // config
50 | if _, found := config["actionDefaultScript"]; !found {
51 | panic("you should specify 'actionDefaultScript' in the config")
52 | }
53 | defaultConfig := ConfigValues{
54 | "debug": false,
55 | "autoUpdate": true,
56 | }
57 | for k, v := range config {
58 | defaultConfig[k] = v
59 | }
60 | a.Config = NewConfigDefaults(a.SupportPath(), defaultConfig)
61 |
62 | a.Cache = NewCache(a.CachePath())
63 | fd, err := os.OpenFile(path.Join(a.SupportPath(), "error.log"), os.O_APPEND|os.O_CREATE|os.O_WRONLY|os.O_SYNC, 0644)
64 | if err != nil {
65 | fd = os.Stderr
66 | }
67 | a.Logger = log.New(fd, "", 0)
68 | c := &Context{
69 | Action: a,
70 | Config: a.Config,
71 | Cache: a.Cache,
72 | Logger: a.Logger,
73 | }
74 | a.context = c
75 | a.Map(c)
76 |
77 | data, err := ioutil.ReadFile(path.Join(a.ActionPath(), "Contents", "Info.plist"))
78 | if err != nil {
79 | a.Logger.Println(err)
80 | panic(err)
81 | }
82 | _, err = plist.Unmarshal(data, &a.info)
83 | if err != nil {
84 | a.Logger.Println(err)
85 | panic(err)
86 | }
87 | return a
88 | }
89 |
90 | // Init parses the input
91 | func (a *Action) Init(m ...FuncMap) *Action {
92 | a.funcs = &FuncMap{}
93 | if m != nil {
94 | *a.funcs = m[0]
95 | }
96 |
97 | in := NewInput(a, os.Args[1:])
98 | a.Input = in
99 | a.context.Input = in
100 |
101 | // TODO: needs good documentation
102 | if in.hasFunc && in.Item.Item().FuncName == "update" {
103 | updateFn := Func(update)
104 | if fn, ok := (*a.funcs)[in.Item.item.FuncName]; ok {
105 | updateFn = fn
106 | }
107 |
108 | vals, err := a.Invoke(updateFn)
109 |
110 | if err != nil {
111 | a.Logger.Fatalln(err)
112 | }
113 | if len(vals) == 0 {
114 | a.Logger.Fatalln("update function should return a value")
115 | }
116 | out, ok := vals[0].Interface().(string)
117 | if !ok {
118 | a.Logger.Fatalf("update function: expected string got: %#v", vals[0].Interface())
119 | }
120 | if a.InDev() {
121 | a.Logger.Println(out)
122 | }
123 | json, err := simplejson.NewJson([]byte(out))
124 | if err != nil {
125 | a.Logger.Fatalf("update function should return a valid json string: %q (%v)", out, err)
126 | }
127 | if _, ok := json.CheckGet("error"); !ok {
128 | a.Logger.Fatalf("update function bad output: %q (%s)", out, "missing 'error'")
129 | }
130 | e, err := json.Get("error").String()
131 | if err != nil {
132 | a.Logger.Fatalf("update function bad output: %q (%s)", out, "'error' is not string")
133 | }
134 |
135 | if e == "" {
136 | _, hasDownload := json.CheckGet("download")
137 | if !hasDownload {
138 | a.Logger.Fatalf("update function bad output: %q (%s)", out, "missing 'download'")
139 | }
140 |
141 | _, hasVersion := json.CheckGet("version")
142 | if !hasVersion {
143 | a.Logger.Fatalf("update function bad output: %q (%s)", out, "missing 'version'")
144 | }
145 |
146 | var changelog string
147 | _, hasChangelog := json.CheckGet("changelog")
148 | if !hasChangelog {
149 | changelog = ""
150 | }
151 | changelog, err = json.Get("changelog").String()
152 | if err != nil {
153 | a.Logger.Fatalf("update function bad output: %q (%s)", out, "'changelog' is not string")
154 | }
155 |
156 | download, err := json.Get("download").String()
157 | if err != nil {
158 | a.Logger.Fatalf("update function bad output: %q (%s)", out, "'download' is not string")
159 | }
160 |
161 | version, err := json.Get("version").String()
162 | if err != nil {
163 | a.Logger.Fatalf("update function bad output: %q (%s)", out, "'version' is not string")
164 | }
165 |
166 | a.Cache.Set("lastUpdate", time.Now(), 7*24*time.Hour)
167 | a.Cache.Set("updateInfo", map[string]string{
168 | "version": version,
169 | "download": download,
170 | "changelog": changelog,
171 | }, 7*24*time.Hour)
172 |
173 | } else {
174 | _, hasDesc := json.CheckGet("description")
175 | if !hasDesc {
176 | a.Logger.Fatalf("update function bad output: %q (%s)", out, "missing 'description'")
177 | }
178 | desc, err := json.Get("description").String()
179 | if err != nil {
180 | a.Logger.Fatalf("update function bad output: %q (%s)", out, "'description' is not string")
181 | }
182 | a.Logger.Println(e, ":", desc)
183 | }
184 |
185 | os.Exit(0)
186 | }
187 |
188 | return a
189 | }
190 |
191 | // Run returns the compiled output of views. You must call Init first
192 | func (a *Action) Run() string {
193 |
194 | // Creating item to handle update
195 | i := a.GetView("main").NewItem("")
196 | i.Item().ID = -1
197 | i.SetOrder(9999)
198 | // i.SetSubtitle("Hold ⌃ to ignore")
199 | i.SetIcon("/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/ToolbarDownloadsFolderIcon.icns")
200 | i.SetActionRunsInBackground(false)
201 | i.SetActionReturnsItems(true)
202 | i.SetRender(func(c *Context) {
203 | oldversion := c.Action.Version()
204 | var updateInfo map[string]string
205 | if _, err := c.Cache.Get("updateInfo", &updateInfo); err != nil {
206 | return
207 | }
208 | newversion := Version(updateInfo["version"])
209 | c.Self.SetTitle(fmt.Sprintf("New Version Available: v%s (I'm v%s)", newversion, oldversion))
210 | })
211 | i.SetMatch(func(c *Context) bool {
212 | oldversion := c.Action.Version()
213 | var updateInfo map[string]string
214 | if _, err := c.Cache.Get("updateInfo", &updateInfo); err != nil {
215 | return false
216 | }
217 | newversion := Version(updateInfo["version"])
218 | return oldversion.Less(newversion)
219 | })
220 | i.SetRun(func(c *Context) *Items {
221 | oldversion := c.Action.Version()
222 | var updateInfo map[string]string
223 | if _, err := c.Cache.Get("updateInfo", &updateInfo); err != nil {
224 | return nil
225 | }
226 | newversion := Version(updateInfo["version"])
227 | if !oldversion.Less(newversion) {
228 | return nil
229 | }
230 | items := NewItems()
231 | items.Add(NewItem(fmt.Sprintf("Download %s", path.Base(updateInfo["download"]))).SetURL(updateInfo["download"]))
232 | for _, line := range strings.Split(updateInfo["changelog"], "\n") {
233 | line = strings.TrimSpace(line)
234 | if line == "" {
235 | continue
236 | }
237 | items.Add(NewItem(line).SetIcon("at.obdev.LaunchBar:ContentsTemplate"))
238 | }
239 | homepage := ""
240 | if desc := a.info["LBDescription"]; desc != nil {
241 | if web := desc.(map[string]interface{})["LBWebsite"]; web != nil {
242 | if s, ok := web.(string); ok {
243 | homepage = s
244 | }
245 | }
246 | }
247 | if homepage != "" {
248 | items.Add(NewItem("Open Homepage").SetURL(homepage))
249 | }
250 | return items
251 | })
252 |
253 | in := a.Input
254 | if in.IsObject() {
255 | if in.hasFunc {
256 | // I'm not sure!
257 | a.context.Self = in.Item
258 | if fn, ok := (*a.funcs)[in.Item.item.FuncName]; ok {
259 | vals, err := a.Invoke(fn)
260 | if err != nil {
261 | a.Logger.Fatalln(err)
262 | }
263 | if len(vals) > 0 {
264 | if vals[0].Interface() != nil {
265 | s := ""
266 | switch res := vals[0].Interface().(type) {
267 |
268 | case Items:
269 | s = res.Compile()
270 | case string:
271 | s = res
272 | case *View:
273 | s = res.Compile()
274 | case *Items:
275 | s = res.Compile()
276 | }
277 | return s
278 | }
279 | }
280 | return ""
281 | }
282 | } else {
283 | if item := a.GetItem(in.Item.item.ID); item != nil {
284 | a.context.Self = item
285 | if item.run != nil {
286 | vals, err := a.Invoke(item.run)
287 | if err != nil {
288 | a.Logger.Fatalln(err)
289 | }
290 | if len(vals) > 0 {
291 | if vals[0].Interface() != nil {
292 | var s string
293 | if out, ok := vals[0].Interface().(Items); ok {
294 | s = out.Compile()
295 | } else {
296 | s = vals[0].Interface().(*Items).Compile()
297 | }
298 | return s
299 | }
300 | }
301 | return ""
302 | }
303 | }
304 | }
305 | }
306 | // TODO: if a.GetView(view) == nil inform the developer
307 | view := a.Config.GetString("view")
308 |
309 | if view == "" {
310 | view = "main"
311 | }
312 |
313 | if view == "main" {
314 | // check for updates
315 | checkForUpdates := false
316 | updateLink := ""
317 | if v := a.info["LBDescription"].(map[string]interface{})["LBUpdate"]; v != nil {
318 | updateLink = v.(string)
319 | }
320 | // lastUpdate := a.Config.GetInt("lastUpdate")
321 | var lastUpdate time.Time
322 | if updateLink != "" {
323 | // TODO: Watch this, IsControlKey, IsOptionKey does not work in LB6102
324 | if a.IsShiftKey() && a.IsOptionKey() {
325 | // TODO: notify the user
326 | a.Logger.Println("Force update.")
327 | checkForUpdates = true
328 | } else if a.Config.GetBool("autoUpdate") {
329 | if _, err := a.Cache.Get("lastUpdate", &lastUpdate); err == nil || err == ErrCacheDoesNotExists {
330 | if lastUpdate.Before(time.Now().AddDate(0, 0, -1)) {
331 | checkForUpdates = true
332 | }
333 | }
334 | }
335 | }
336 | if checkForUpdates {
337 | if a.InDev() {
338 | a.Logger.Println("Checking for update...")
339 | out, _ := exec.Command(os.Args[0], `{"x-func":"update"}`).CombinedOutput()
340 | if s := strings.TrimSpace(string(out)); s != "" {
341 | a.Logger.Println(s)
342 | }
343 | } else {
344 | exec.Command(os.Args[0], `{"x-func":"update"}`).Start()
345 | }
346 | }
347 | }
348 |
349 | w := a.GetView("*")
350 | out := a.GetView(view).Join(w).Compile()
351 | return out
352 | }
353 |
354 | // ShowView reruns the LaunchBar with the specified view.
355 | //
356 | // Use this when your LiveFeedback is enabled and you want to show another view
357 | func (a *Action) ShowView(v string) {
358 | a.Config.Set("view", v)
359 | exec.Command("osascript", "-e", fmt.Sprintf(`tell application "LaunchBar"
360 | remain active
361 | perform action "%s"
362 | end tell`, a.name)).Start()
363 | }
364 |
365 | // NewView created a new view ready to populate with Items
366 | func (a *Action) NewView(name string) *View {
367 | v := &View{a, name, make(Items, 0)}
368 | a.views[name] = v
369 | return v
370 | }
371 |
372 | // GetView returns a View if the view is not defined returns nil
373 | func (a *Action) GetView(v string) *View {
374 | view, ok := a.views[v]
375 | if ok {
376 | return view
377 | }
378 | return nil
379 | }
380 |
381 | // GetItem return an Item with its ID. Returns nil if not found.
382 | func (a *Action) GetItem(id int) *Item {
383 | for _, item := range a.items {
384 | if item.Item().ID == id {
385 | return item
386 | }
387 | }
388 | return nil
389 | }
390 |
391 | // InDev returns true if the config.indev is true
392 | func (a *Action) InDev() bool { return a.Config.GetBool("indev") }
393 |
394 | // Info.plist variables
395 |
396 | // Varsion returns Action version specified by CFBundleVersion key in Info.plist
397 | func (a *Action) Version() Version { return Version(a.info["CFBundleVersion"].(string)) }
398 |
399 | // LaunchBar provided variabled
400 |
401 | // ActionPath returns the absolute path to the .lbaction bundle.
402 | func (a *Action) ActionPath() string { return os.Getenv("LB_ACTION_PATH") }
403 |
404 | // CachePath returns the absolute path to the action’s cache directory:
405 | // ~/Library/Caches/at.obdev.LaunchBar/Actions/Action Bundle Identifier/
406 | //
407 | // The action’s cache directory can be used to store files that can be recreated
408 | // by the action itself, e.g. by downloading a file from a server again.
409 | //
410 | // Currently, this directory’s contents will never be touched by LaunchBar,
411 | // but it may be periodically cleared in a future release.
412 | // When the action is run, this directory is guaranteed to exist.
413 | func (a *Action) CachePath() string { return os.Getenv("LB_CACHE_PATH") }
414 |
415 | // Supportpath returns the The absolute path to the action’s support directory:
416 | // ~/Library/Application Support/LaunchBar/Action Support/Action Bundle Identifier/
417 | //
418 | // The action support directory can be used to persist user data between runs of
419 | // the action, like preferences. When the action is run, this directory is
420 | // guaranteed to exist.
421 | func (a *Action) SupportPath() string { return os.Getenv("LB_SUPPORT_PATH") }
422 |
423 | // IsDebug returns the value corresponds to LBDebugLogEnabled in the action’s Info.plist.
424 | func (a *Action) IsDebug() bool { return os.Getenv("LB_DEBUG_LOG_ENABLED") == "true" }
425 |
426 | // Launchbarpath returns the path to the LaunchBar.app bundle.
427 | func (a *Action) LaunchBarPath() string { return os.Getenv("LB_LAUNCHBAR_PATH") }
428 |
429 | // ScriptType returns the type of the script, as defined by the action’s Info.plist.
430 | //
431 | // This is either “default”, “suggestions” or “actionURL”.
432 | //
433 | // See http://www.obdev.at/resources/launchbar/developer-documentation/action-programming-guide.html#script-types for more information.
434 | func (a *Action) ScriptType() string { return os.Getenv("LB_SCRIPT_TYPE") }
435 |
436 | // IsCommandKey returns true if the Command key was down while running the action.
437 | func (a *Action) IsCommandKey() bool { return os.Getenv("LB_OPTION_COMMAND_KEY") == "1" }
438 |
439 | // IsOptionKey returns true if the Alternate (Option) key was down while running the action.
440 | func (a *Action) IsOptionKey() bool { return os.Getenv("LB_OPTION_ALTERNATE_KEY") == "1" }
441 |
442 | // IsShiftKey returns true if the Shift key was down while running the action.
443 | func (a *Action) IsShiftKey() bool { return os.Getenv("LB_OPTION_SHIFT_KEY") == "1" }
444 |
445 | // IsControlKey returns true if the Control key was down while running the action.
446 | func (a *Action) IsControlKey() bool { return os.Getenv("LB_OPTION_CONTROL_KEY") == "1" }
447 |
448 | // IsBackground returns true if the action is running in background.
449 | func (a *Action) IsBackground() bool { return os.Getenv("LB_OPTION_RUN_IN_BACKGROUND") == "1" }
450 |
--------------------------------------------------------------------------------
/vendor/src/github.com/nbjahan/go-launchbar/update.go:
--------------------------------------------------------------------------------
1 | package launchbar
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "io/ioutil"
7 | "net/http"
8 |
9 | "time"
10 |
11 | "github.com/DHowett/go-plist"
12 | )
13 |
14 | func update(c *Context) string {
15 | updateLink := c.Action.info["LBDescription"].(map[string]interface{})["LBUpdate"].(string)
16 | var updateStartTime time.Time
17 | if _, err := c.Cache.Get("updateStartTime", &updateStartTime); err == nil {
18 | return die("update in progress", fmt.Sprintf("update check in progress (started %v ago)", time.Now().Sub(updateStartTime)))
19 | }
20 | c.Cache.Set("updateStartTime", time.Now(), 3*time.Minute)
21 | defer func() {
22 | c.Cache.Delete("updateStartTime")
23 | }()
24 |
25 | var data, updatePlist []byte
26 | var etag, updateETag string
27 | c.Cache.Get("updateETag", &etag)
28 | if etag != "" {
29 | resp, err := http.Head(updateLink)
30 | if err != nil {
31 | return die("cannot get updateLink", fmt.Sprintf("%v", err))
32 | }
33 | updateETag = resp.Header.Get("etag")
34 | if etag == updateETag {
35 | c.Cache.Get("updatePlist", &updatePlist)
36 | if len(updatePlist) != 0 {
37 | data = updatePlist
38 | }
39 | }
40 | }
41 |
42 | if len(data) == 0 {
43 | resp, err := http.Get(updateLink)
44 | if err != nil {
45 | return die("cannot get updateLink", fmt.Sprintf("%v", err))
46 | }
47 | if resp.StatusCode >= 400 {
48 | return die("cannot get updateLink", fmt.Sprintf("%v", resp.Status))
49 | }
50 | defer resp.Body.Close()
51 | data, err = ioutil.ReadAll(resp.Body)
52 | if err != nil {
53 | return die("cannot get updateLink", fmt.Sprintf("%v", err))
54 | }
55 | c.Cache.Set("updateETag", resp.Header.Get("etag"), 0)
56 | c.Cache.Set("updatePlist", data, 0)
57 | }
58 |
59 | var v map[string]interface{}
60 | _, err := plist.Unmarshal(data, &v)
61 | if err != nil {
62 | return die("cannot parse updateLink", fmt.Sprintf("Error: %v\nData: %s", err, string(data)))
63 | }
64 |
65 | var updateVersion, updateDownload, updateChangelog string
66 |
67 | if v["CFBundleVersion"] != nil {
68 | if s, ok := v["CFBundleVersion"].(string); ok {
69 | updateVersion = s
70 | }
71 | }
72 | if updateVersion == "" {
73 | return die("no remote version", "cannot get the remote version!")
74 | }
75 |
76 | if v["LBDescription"] != nil && v["LBDescription"].(map[string]interface{}) != nil {
77 | if v["LBDescription"].(map[string]interface{})["LBDownload"] != nil {
78 | if s, ok := v["LBDescription"].(map[string]interface{})["LBDownload"].(string); ok {
79 | updateDownload = s
80 | }
81 | }
82 | if updateDownload == "" {
83 | return die("no remote download", "cannot get the remote download link!")
84 | }
85 |
86 | if v["LBDescription"].(map[string]interface{})["LBChangelog"] != nil {
87 | if s, ok := v["LBDescription"].(map[string]interface{})["LBChangelog"].(string); ok {
88 | updateChangelog = s
89 | }
90 | }
91 | }
92 |
93 | return write(map[string]interface{}{
94 | "error": "",
95 | "version": updateVersion,
96 | "download": updateDownload,
97 | "changelog": updateChangelog,
98 | })
99 | }
100 |
101 | func write(m map[string]interface{}) string {
102 | data, err := json.Marshal(m)
103 |
104 | if err != nil {
105 | return "\"\""
106 | }
107 | return string(data)
108 | }
109 |
110 | func die(err, desc string) string {
111 | return write(map[string]interface{}{
112 | "error": err,
113 | "description": desc,
114 | })
115 | }
116 |
--------------------------------------------------------------------------------
/vendor/src/github.com/nbjahan/go-launchbar/version.go:
--------------------------------------------------------------------------------
1 | package launchbar
2 |
3 | import (
4 | "strconv"
5 | "strings"
6 | )
7 |
8 | // Version represents a version string (e.g. 1.0, 1.0, 1.0.0)
9 | type Version string
10 |
11 | func parseVersion(s string) (major, minor, patch int) {
12 | components := [3]int{0, 0, 0}
13 | parts := strings.Split(s, ".")
14 | for i, part := range parts {
15 | parti, _ := strconv.Atoi(part)
16 | components[i] = parti
17 | }
18 | major, minor, patch = components[0], components[1], components[2]
19 | return
20 | }
21 |
22 | // Cmp compares v and w and returns
23 | // -1 if v < w
24 | // 0 if v == w
25 | // +1 if v > w
26 | func (v Version) Cmp(w Version) int {
27 | v0, v1, v2 := parseVersion(string(v))
28 | w0, w1, w2 := parseVersion(string(w))
29 | switch {
30 | case v0 > w0:
31 | return 1
32 | case v0 < w0:
33 | return -1
34 | case v1 > w1:
35 | return 1
36 | case v1 < w1:
37 | return -1
38 | case v2 > w2:
39 | return 1
40 | case v2 < w2:
41 | return -1
42 | }
43 | return 0
44 | }
45 |
46 | // Less returns true if v < w
47 | // Example:
48 | // Version("0.1.0").Less(Version("1.0")) == true
49 | func (v Version) Less(w Version) bool {
50 | return v.Cmp(w) < 0
51 | }
52 |
53 | // Equal returns true if v == w
54 | // Example:
55 | // Version("1.0").Equal(Version("1")) == true
56 | func (v Version) Equal(w Version) bool {
57 | return v.Cmp(w) == 0
58 | }
59 |
--------------------------------------------------------------------------------
/vendor/src/github.com/nbjahan/go-launchbar/version_test.go:
--------------------------------------------------------------------------------
1 | package launchbar
2 |
3 | import "testing"
4 |
5 | func TestVersionCmp(t *testing.T) {
6 | tests := []struct {
7 | a, b string
8 | out int
9 | }{
10 | {"1.0.0", "1.0.0", 0},
11 | {"0", "0.1", -1},
12 | {"0", "1", -1},
13 | {"0.0", "0.0", 0},
14 | {"0.0.0", "0.0.0", 0},
15 | {"0.1", "0", 1},
16 | {"0.1", "0.1", 0},
17 | {"0.1", "1.0", -1},
18 | {"0.1.0", "1.0", -1},
19 | {"0.1.0", "1.1.0", -1},
20 | {"1", "0", 1},
21 | {"1", "1", 0},
22 | {"1.0", "0", 1},
23 | {"1.0", "0.9", 1},
24 | {"1.0", "1", 0},
25 | {"1.0", "1.0", 0},
26 | {"1.0.0", "0", 1},
27 | {"1.0.0", "0.0", 1},
28 | {"1.0.0", "0.0.0", 1},
29 | {"1.0.0", "1", 0},
30 | {"1.0.0", "1.0", 0},
31 | {"1.0.0", "1.0.1", -1},
32 | {"1.0.0", "1.1.0", -1},
33 | {"1.0.0", "1.1.1", -1},
34 | {"1.1", "1.0.1", 1},
35 | {"1.1.0", "1.0.0", 1},
36 | {"1.1.1", "1.2", -1},
37 | {"1.2.1", "1.2", 1},
38 | {"11.0.1", "10.9.1", 1},
39 | {"11.1.2", "11.1.3", -1},
40 | {"1.12", "1.11", 1},
41 | {"1.12", "1.12", 0},
42 | {"1.12", "1.13", -1},
43 | }
44 |
45 | for _, test := range tests {
46 | out := Version(test.a).Cmp(Version(test.b))
47 | if out != test.out {
48 | t.Errorf("%q Cmp %q? expected %v, got %v", test.a, test.b, test.out, out)
49 | }
50 | }
51 | }
52 |
53 | func TestVersionEqual(t *testing.T) {
54 | tests := []struct {
55 | a, b string
56 | out bool
57 | }{
58 | {"1.0.0", "1.0.0", true},
59 | {"1.0.0", "1.0", true},
60 | {"1.0.0", "1", true},
61 | {"1.0", "1.0", true},
62 | {"1.0", "1", true},
63 | {"1", "1", true},
64 | {"1.0.0", "0.0.0", false},
65 | {"1.0.0", "0.0", false},
66 | {"1.0.0", "0", false},
67 | {"1.0", "0", false},
68 | {"1", "0", false},
69 | {"1.12", "1.12", true},
70 | {"1.12", "1.012", true},
71 | {"1.12", "1.13", false},
72 | }
73 |
74 | for _, test := range tests {
75 | out := Version(test.a).Equal(Version(test.b))
76 | if out != test.out {
77 | t.Errorf("%q Equal %q? expected %v, got %v", test.a, test.b, test.out, out)
78 | }
79 | }
80 | }
81 |
82 | func TestVersionLess(t *testing.T) {
83 | tests := []struct {
84 | a, b string
85 | out bool
86 | }{
87 | {"0.0.0", "0.0.0", false},
88 | {"0.0", "0.0", false},
89 | {"0", "1", true},
90 | {"1.0.0", "1.0.1", true},
91 | {"1.0.0", "1.1.1", true},
92 | {"1.0.0", "1.1.0", true},
93 | {"0.1.0", "1.1.0", true},
94 | {"1.1.0", "1.0.0", false},
95 | {"1.0", "0.9", false},
96 | {"11.0.1", "10.9.1", false},
97 | {"11.1.2", "11.1.3", true},
98 | {"1.1", "1.0.1", false},
99 | {"1.1.1", "1.2", true},
100 | {"1.2.1", "1.2", false},
101 | {"0.1", "1.0", true},
102 | {"0.1", "0.1", false},
103 | {"0.1", "0", false},
104 | {"0", "0.1", true},
105 | {"0.1.0", "1.0", true},
106 | {"0.12", "0.13", true},
107 | {"0.12", "1.12", true},
108 | {"0.12", "0.12", false},
109 | }
110 |
111 | for _, test := range tests {
112 | out := Version(test.a).Less(Version(test.b))
113 | if out != test.out {
114 | t.Errorf("%q Less than %q? expected %v, got %v", test.a, test.b, test.out, out)
115 | }
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/vendor/src/github.com/nbjahan/go-launchbar/view.go:
--------------------------------------------------------------------------------
1 | package launchbar
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "sort"
7 | )
8 |
9 | // View represents collection of Items in LaunchBar
10 | type View struct {
11 | Action *Action
12 | Name string
13 | Items Items
14 | }
15 |
16 | // NewItem creates an always matching Item that runs in background and adds it to the view.
17 | func (v *View) NewItem(title string) *Item {
18 | i := &Item{View: v, item: &item{Title: title}}
19 | i.SetActionRunsInBackground(true).
20 | SetAction(i.View.Action.Config.GetString("actionDefaultScript")).
21 | SetMatch(AlwasMatch)
22 | i.item.ID = len(v.Action.items) + 1
23 | i.SetOrder(len(v.Items))
24 | v.Items = append(v.Items, i)
25 | v.Action.items = append(v.Action.items, i)
26 | return i
27 | }
28 |
29 | // AddItem add an Item to the view
30 | func (v *View) AddItem(item *Item) *View {
31 | item.View = v
32 | if item.match == nil {
33 | item.SetMatch(AlwasMatch)
34 | }
35 | item.item.ID = len(v.Action.items) + 1
36 | v.Items = append(v.Items, item)
37 | v.Action.items = append(v.Action.items, item)
38 | return v
39 | }
40 |
41 | // Render executes each Item Render, Match functions and returns them.
42 | func (v *View) Render() Items {
43 | if len(v.Items) == 0 {
44 | return Items(nil)
45 | }
46 |
47 | items := &Items{}
48 | for _, item := range v.Items {
49 | v.Action.context.Self = item
50 | if item.match != nil {
51 | vals, err := v.Action.Invoke(item.match)
52 | if err != nil {
53 | v.Action.Logger.Fatalln(err)
54 | panic(err)
55 | }
56 | if len(vals) > 0 {
57 | if !vals[0].Bool() {
58 | continue
59 | }
60 | }
61 | }
62 | if item.render != nil {
63 | _, err := v.Action.Invoke(item.render)
64 | if err != nil {
65 | v.Action.Logger.Fatalln(err)
66 | panic(err)
67 | }
68 | }
69 | item.item.Arg = v.Action.Input.String()
70 | items.Add(item)
71 | }
72 | sort.Sort(itemsByOrder(*items))
73 |
74 | return *items
75 |
76 | }
77 |
78 | // Compile renders and output the view.Items as a json string.
79 | func (v *View) Compile() string {
80 | items := v.Render()
81 |
82 | if items == nil {
83 | return ""
84 | }
85 |
86 | b, err := json.Marshal(items.getItems())
87 | if err != nil {
88 | return fmt.Sprintf(`[{"title": "%v","subtitle":"error"}]`, err)
89 | }
90 | return string(b)
91 | }
92 |
93 | // Join returns a new view with the items of v, w
94 | func (v *View) Join(w *View) *View {
95 | if w == nil {
96 | return v
97 | }
98 | return &View{v.Action, v.Name, append(v.Items, w.Items...)}
99 | }
100 |
--------------------------------------------------------------------------------