├── .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 | ![](img/livedic.png) 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 | --------------------------------------------------------------------------------