4
0
mirror of https://github.com/cwinfo/matterbridge.git synced 2025-07-05 03:34:03 +00:00

Add Mumble support (#1245)

This commit is contained in:
Sebastian P
2020-10-01 22:50:56 +02:00
committed by GitHub
parent e7781dc79c
commit 214a6a1386
61 changed files with 9409 additions and 0 deletions

20
vendor/github.com/vincent-petithory/dataurl/LICENSE generated vendored Normal file
View File

@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2014 Vincent Petithory
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

81
vendor/github.com/vincent-petithory/dataurl/README.md generated vendored Normal file
View File

@ -0,0 +1,81 @@
# Data URL Schemes for Go [![wercker status](https://app.wercker.com/status/6f9a2e144dfcc59e862c52459b452928/s "wercker status")](https://app.wercker.com/project/bykey/6f9a2e144dfcc59e862c52459b452928) [![GoDoc](https://godoc.org/github.com/vincent-petithory/dataurl?status.png)](https://godoc.org/github.com/vincent-petithory/dataurl)
This package parses and generates Data URL Schemes for the Go language, according to [RFC 2397](http://tools.ietf.org/html/rfc2397).
Data URLs are small chunks of data commonly used in browsers to display inline data,
typically like small images, or when you use the FileReader API of the browser.
Common use-cases:
* generate a data URL out of a `string`, `[]byte`, `io.Reader` for inclusion in HTML templates,
* parse a data URL sent by a browser in a http.Handler, and do something with the data (save to disk, etc.)
* ...
Install the package with:
~~~
go get github.com/vincent-petithory/dataurl
~~~
## Usage
~~~ go
package main
import (
"github.com/vincent-petithory/dataurl"
"fmt"
)
func main() {
dataURL, err := dataurl.DecodeString(`data:text/plain;charset=utf-8;base64,aGV5YQ==`)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("content type: %s, data: %s\n", dataURL.MediaType.ContentType(), string(dataURL.Data))
// Output: content type: text/plain, data: heya
}
~~~
From a `http.Handler`:
~~~ go
func handleDataURLUpload(w http.ResponseWriter, r *http.Request) {
dataURL, err := dataurl.Decode(r.Body)
defer r.Body.Close()
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
if dataURL.ContentType() == "image/png" {
ioutil.WriteFile("image.png", dataURL.Data, 0644)
} else {
http.Error(w, "not a png", http.StatusBadRequest)
}
}
~~~
## Command
For convenience, a `dataurl` command is provided to encode/decode dataurl streams.
~~~
dataurl - Encode or decode dataurl data and print to standard output
Usage: dataurl [OPTION]... [FILE]
dataurl encodes or decodes FILE or standard input if FILE is - or omitted, and prints to standard output.
Unless -mimetype is used, when FILE is specified, dataurl will attempt to detect its mimetype using Go's mime.TypeByExtension (http://golang.org/pkg/mime/#TypeByExtension). If this fails or data is read from STDIN, the mimetype will default to application/octet-stream.
Options:
-a=false: encode data using ascii instead of base64
-ascii=false: encode data using ascii instead of base64
-d=false: decode data instead of encoding
-decode=false: decode data instead of encoding
-m="": force the mimetype of the data to encode to this value
-mimetype="": force the mimetype of the data to encode to this value
~~~
## Contributing
Feel free to file an issue/make a pull request if you find any bug, or want to suggest enhancements.

291
vendor/github.com/vincent-petithory/dataurl/dataurl.go generated vendored Normal file
View File

@ -0,0 +1,291 @@
package dataurl
import (
"bytes"
"encoding/base64"
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
"sort"
"strconv"
"strings"
)
const (
// EncodingBase64 is base64 encoding for the data url
EncodingBase64 = "base64"
// EncodingASCII is ascii encoding for the data url
EncodingASCII = "ascii"
)
func defaultMediaType() MediaType {
return MediaType{
"text",
"plain",
map[string]string{"charset": "US-ASCII"},
}
}
// MediaType is the combination of a media type, a media subtype
// and optional parameters.
type MediaType struct {
Type string
Subtype string
Params map[string]string
}
// ContentType returns the content type of the dataurl's data, in the form type/subtype.
func (mt *MediaType) ContentType() string {
return fmt.Sprintf("%s/%s", mt.Type, mt.Subtype)
}
// String implements the Stringer interface.
//
// Params values are escaped with the Escape function, rather than in a quoted string.
func (mt *MediaType) String() string {
var (
buf bytes.Buffer
keys = make([]string, len(mt.Params))
i int
)
for k := range mt.Params {
keys[i] = k
i++
}
sort.Strings(keys)
for _, k := range keys {
v := mt.Params[k]
fmt.Fprintf(&buf, ";%s=%s", k, EscapeString(v))
}
return mt.ContentType() + (&buf).String()
}
// DataURL is the combination of a MediaType describing the type of its Data.
type DataURL struct {
MediaType
Encoding string
Data []byte
}
// New returns a new DataURL initialized with data and
// a MediaType parsed from mediatype and paramPairs.
// mediatype must be of the form "type/subtype" or it will panic.
// paramPairs must have an even number of elements or it will panic.
// For more complex DataURL, initialize a DataURL struct.
// The DataURL is initialized with base64 encoding.
func New(data []byte, mediatype string, paramPairs ...string) *DataURL {
parts := strings.Split(mediatype, "/")
if len(parts) != 2 {
panic("dataurl: invalid mediatype")
}
nParams := len(paramPairs)
if nParams%2 != 0 {
panic("dataurl: requires an even number of param pairs")
}
params := make(map[string]string)
for i := 0; i < nParams; i += 2 {
params[paramPairs[i]] = paramPairs[i+1]
}
mt := MediaType{
parts[0],
parts[1],
params,
}
return &DataURL{
MediaType: mt,
Encoding: EncodingBase64,
Data: data,
}
}
// String implements the Stringer interface.
//
// Note: it doesn't guarantee the returned string is equal to
// the initial source string that was used to create this DataURL.
// The reasons for that are:
// * Insertion of default values for MediaType that were maybe not in the initial string,
// * Various ways to encode the MediaType parameters (quoted string or url encoded string, the latter is used),
func (du *DataURL) String() string {
var buf bytes.Buffer
du.WriteTo(&buf)
return (&buf).String()
}
// WriteTo implements the WriterTo interface.
// See the note about String().
func (du *DataURL) WriteTo(w io.Writer) (n int64, err error) {
var ni int
ni, _ = fmt.Fprint(w, "data:")
n += int64(ni)
ni, _ = fmt.Fprint(w, du.MediaType.String())
n += int64(ni)
if du.Encoding == EncodingBase64 {
ni, _ = fmt.Fprint(w, ";base64")
n += int64(ni)
}
ni, _ = fmt.Fprint(w, ",")
n += int64(ni)
if du.Encoding == EncodingBase64 {
encoder := base64.NewEncoder(base64.StdEncoding, w)
ni, err = encoder.Write(du.Data)
if err != nil {
return
}
encoder.Close()
} else if du.Encoding == EncodingASCII {
ni, _ = fmt.Fprint(w, Escape(du.Data))
n += int64(ni)
} else {
err = fmt.Errorf("dataurl: invalid encoding %s", du.Encoding)
return
}
return
}
// UnmarshalText decodes a Data URL string and sets it to *du
func (du *DataURL) UnmarshalText(text []byte) error {
decoded, err := DecodeString(string(text))
if err != nil {
return err
}
*du = *decoded
return nil
}
// MarshalText writes du as a Data URL
func (du *DataURL) MarshalText() ([]byte, error) {
buf := bytes.NewBuffer(nil)
if _, err := du.WriteTo(buf); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
type encodedDataReader func(string) ([]byte, error)
var asciiDataReader encodedDataReader = func(s string) ([]byte, error) {
us, err := Unescape(s)
if err != nil {
return nil, err
}
return []byte(us), nil
}
var base64DataReader encodedDataReader = func(s string) ([]byte, error) {
data, err := base64.StdEncoding.DecodeString(s)
if err != nil {
return nil, err
}
return []byte(data), nil
}
type parser struct {
du *DataURL
l *lexer
currentAttr string
unquoteParamVal bool
encodedDataReaderFn encodedDataReader
}
func (p *parser) parse() error {
for item := range p.l.items {
switch item.t {
case itemError:
return errors.New(item.String())
case itemMediaType:
p.du.MediaType.Type = item.val
// Should we clear the default
// "charset" parameter at this point?
delete(p.du.MediaType.Params, "charset")
case itemMediaSubType:
p.du.MediaType.Subtype = item.val
case itemParamAttr:
p.currentAttr = item.val
case itemLeftStringQuote:
p.unquoteParamVal = true
case itemParamVal:
val := item.val
if p.unquoteParamVal {
p.unquoteParamVal = false
us, err := strconv.Unquote("\"" + val + "\"")
if err != nil {
return err
}
val = us
} else {
us, err := UnescapeToString(val)
if err != nil {
return err
}
val = us
}
p.du.MediaType.Params[p.currentAttr] = val
case itemBase64Enc:
p.du.Encoding = EncodingBase64
p.encodedDataReaderFn = base64DataReader
case itemDataComma:
if p.encodedDataReaderFn == nil {
p.encodedDataReaderFn = asciiDataReader
}
case itemData:
reader, err := p.encodedDataReaderFn(item.val)
if err != nil {
return err
}
p.du.Data = reader
case itemEOF:
if p.du.Data == nil {
p.du.Data = []byte("")
}
return nil
}
}
panic("EOF not found")
}
// DecodeString decodes a Data URL scheme string.
func DecodeString(s string) (*DataURL, error) {
du := &DataURL{
MediaType: defaultMediaType(),
Encoding: EncodingASCII,
}
parser := &parser{
du: du,
l: lex(s),
}
if err := parser.parse(); err != nil {
return nil, err
}
return du, nil
}
// Decode decodes a Data URL scheme from a io.Reader.
func Decode(r io.Reader) (*DataURL, error) {
data, err := ioutil.ReadAll(r)
if err != nil {
return nil, err
}
return DecodeString(string(data))
}
// EncodeBytes encodes the data bytes into a Data URL string, using base 64 encoding.
//
// The media type of data is detected using http.DetectContentType.
func EncodeBytes(data []byte) string {
mt := http.DetectContentType(data)
// http.DetectContentType may add spurious spaces between ; and a parameter.
// The canonical way is to not have them.
cleanedMt := strings.Replace(mt, "; ", ";", -1)
return New(data, cleanedMt).String()
}

28
vendor/github.com/vincent-petithory/dataurl/doc.go generated vendored Normal file
View File

@ -0,0 +1,28 @@
/*
Package dataurl parses Data URL Schemes
according to RFC 2397
(http://tools.ietf.org/html/rfc2397).
Data URLs are small chunks of data commonly used in browsers to display inline data,
typically like small images, or when you use the FileReader API of the browser.
A dataurl looks like:
data:text/plain;charset=utf-8,A%20brief%20note
Or, with base64 encoding:
data:image/vnd.microsoft.icon;name=golang%20favicon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAD///8AVE44//7hdv/+4Xb//uF2//7hdv/+4Xb//uF2//7hdv/+4Xb//uF2//7hdv/+4Xb/
/uF2/1ROOP////8A////AFROOP/+4Xb//uF2//7hdv/+4Xb//uF2//7hdv/+4Xb//uF2//7hdv/+
...
/6CcjP97c07/e3NO/1dOMf9BOiX/TkUn/2VXLf97c07/e3NO/6CcjP/h4uX/////AP///wD///8A
////AP///wD///8A////AP///wDq6/H/3N/j/9fZ3f/q6/H/////AP///wD///8A////AP///wD/
//8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAA==
Common functions are Decode and DecodeString to obtain a DataURL,
and DataURL.String() and DataURL.WriteTo to generate a Data URL string.
*/
package dataurl

521
vendor/github.com/vincent-petithory/dataurl/lex.go generated vendored Normal file
View File

@ -0,0 +1,521 @@
package dataurl
import (
"fmt"
"strings"
"unicode"
"unicode/utf8"
)
type item struct {
t itemType
val string
}
func (i item) String() string {
switch i.t {
case itemEOF:
return "EOF"
case itemError:
return i.val
}
if len(i.val) > 10 {
return fmt.Sprintf("%.10q...", i.val)
}
return fmt.Sprintf("%q", i.val)
}
type itemType int
const (
itemError itemType = iota
itemEOF
itemDataPrefix
itemMediaType
itemMediaSep
itemMediaSubType
itemParamSemicolon
itemParamAttr
itemParamEqual
itemLeftStringQuote
itemRightStringQuote
itemParamVal
itemBase64Enc
itemDataComma
itemData
)
const eof rune = -1
func isTokenRune(r rune) bool {
return r <= unicode.MaxASCII &&
!unicode.IsControl(r) &&
!unicode.IsSpace(r) &&
!isTSpecialRune(r)
}
func isTSpecialRune(r rune) bool {
return r == '(' ||
r == ')' ||
r == '<' ||
r == '>' ||
r == '@' ||
r == ',' ||
r == ';' ||
r == ':' ||
r == '\\' ||
r == '"' ||
r == '/' ||
r == '[' ||
r == ']' ||
r == '?' ||
r == '='
}
// See http://tools.ietf.org/html/rfc2045
// This doesn't include extension-token case
// as it's handled separatly
func isDiscreteType(s string) bool {
if strings.HasPrefix(s, "text") ||
strings.HasPrefix(s, "image") ||
strings.HasPrefix(s, "audio") ||
strings.HasPrefix(s, "video") ||
strings.HasPrefix(s, "application") {
return true
}
return false
}
// See http://tools.ietf.org/html/rfc2045
// This doesn't include extension-token case
// as it's handled separatly
func isCompositeType(s string) bool {
if strings.HasPrefix(s, "message") ||
strings.HasPrefix(s, "multipart") {
return true
}
return false
}
func isURLCharRune(r rune) bool {
// We're a bit permissive here,
// by not including '%' in delims
// This is okay, since url unescaping will validate
// that later in the parser.
return r <= unicode.MaxASCII &&
!(r >= 0x00 && r <= 0x1F) && r != 0x7F && /* control */
// delims
r != ' ' &&
r != '<' &&
r != '>' &&
r != '#' &&
r != '"' &&
// unwise
r != '{' &&
r != '}' &&
r != '|' &&
r != '\\' &&
r != '^' &&
r != '[' &&
r != ']' &&
r != '`'
}
func isBase64Rune(r rune) bool {
return (r >= 'a' && r <= 'z') ||
(r >= 'A' && r <= 'Z') ||
(r >= '0' && r <= '9') ||
r == '+' ||
r == '/' ||
r == '=' ||
r == '\n'
}
type stateFn func(*lexer) stateFn
// lexer lexes the data URL scheme input string.
// The implementation is from the text/template/parser package.
type lexer struct {
input string
start int
pos int
width int
seenBase64Item bool
items chan item
}
func (l *lexer) run() {
for state := lexBeforeDataPrefix; state != nil; {
state = state(l)
}
close(l.items)
}
func (l *lexer) emit(t itemType) {
l.items <- item{t, l.input[l.start:l.pos]}
l.start = l.pos
}
func (l *lexer) next() (r rune) {
if l.pos >= len(l.input) {
l.width = 0
return eof
}
r, l.width = utf8.DecodeRuneInString(l.input[l.pos:])
l.pos += l.width
return r
}
func (l *lexer) backup() {
l.pos -= l.width
}
func (l *lexer) ignore() {
l.start = l.pos
}
func (l *lexer) errorf(format string, args ...interface{}) stateFn {
l.items <- item{itemError, fmt.Sprintf(format, args...)}
return nil
}
func lex(input string) *lexer {
l := &lexer{
input: input,
items: make(chan item),
}
go l.run() // Concurrently run state machine.
return l
}
const (
dataPrefix = "data:"
mediaSep = '/'
paramSemicolon = ';'
paramEqual = '='
dataComma = ','
)
// start lexing by detecting data prefix
func lexBeforeDataPrefix(l *lexer) stateFn {
if strings.HasPrefix(l.input[l.pos:], dataPrefix) {
return lexDataPrefix
}
return l.errorf("missing data prefix")
}
// lex data prefix
func lexDataPrefix(l *lexer) stateFn {
l.pos += len(dataPrefix)
l.emit(itemDataPrefix)
return lexAfterDataPrefix
}
// lex what's after data prefix.
// it can be the media type/subtype separator,
// the base64 encoding, or the comma preceding the data
func lexAfterDataPrefix(l *lexer) stateFn {
switch r := l.next(); {
case r == paramSemicolon:
l.backup()
return lexParamSemicolon
case r == dataComma:
l.backup()
return lexDataComma
case r == eof:
return l.errorf("missing comma before data")
case r == 'x' || r == 'X':
if l.next() == '-' {
return lexXTokenMediaType
}
return lexInDiscreteMediaType
case isTokenRune(r):
return lexInDiscreteMediaType
default:
return l.errorf("invalid character after data prefix")
}
}
func lexXTokenMediaType(l *lexer) stateFn {
for {
switch r := l.next(); {
case r == mediaSep:
l.backup()
return lexMediaType
case r == eof:
return l.errorf("missing media type slash")
case isTokenRune(r):
default:
return l.errorf("invalid character for media type")
}
}
}
func lexInDiscreteMediaType(l *lexer) stateFn {
for {
switch r := l.next(); {
case r == mediaSep:
l.backup()
// check it's valid discrete type
if !isDiscreteType(l.input[l.start:l.pos]) &&
!isCompositeType(l.input[l.start:l.pos]) {
return l.errorf("invalid media type")
}
return lexMediaType
case r == eof:
return l.errorf("missing media type slash")
case isTokenRune(r):
default:
return l.errorf("invalid character for media type")
}
}
}
func lexMediaType(l *lexer) stateFn {
if l.pos > l.start {
l.emit(itemMediaType)
}
return lexMediaSep
}
func lexMediaSep(l *lexer) stateFn {
l.next()
l.emit(itemMediaSep)
return lexAfterMediaSep
}
func lexAfterMediaSep(l *lexer) stateFn {
for {
switch r := l.next(); {
case r == paramSemicolon || r == dataComma:
l.backup()
return lexMediaSubType
case r == eof:
return l.errorf("incomplete media type")
case isTokenRune(r):
default:
return l.errorf("invalid character for media subtype")
}
}
}
func lexMediaSubType(l *lexer) stateFn {
if l.pos > l.start {
l.emit(itemMediaSubType)
}
return lexAfterMediaSubType
}
func lexAfterMediaSubType(l *lexer) stateFn {
switch r := l.next(); {
case r == paramSemicolon:
l.backup()
return lexParamSemicolon
case r == dataComma:
l.backup()
return lexDataComma
case r == eof:
return l.errorf("missing comma before data")
default:
return l.errorf("expected semicolon or comma")
}
}
func lexParamSemicolon(l *lexer) stateFn {
l.next()
l.emit(itemParamSemicolon)
return lexAfterParamSemicolon
}
func lexAfterParamSemicolon(l *lexer) stateFn {
switch r := l.next(); {
case r == eof:
return l.errorf("unterminated parameter sequence")
case r == paramEqual || r == dataComma:
return l.errorf("unterminated parameter sequence")
case isTokenRune(r):
l.backup()
return lexInParamAttr
default:
return l.errorf("invalid character for parameter attribute")
}
}
func lexBase64Enc(l *lexer) stateFn {
if l.pos > l.start {
if v := l.input[l.start:l.pos]; v != "base64" {
return l.errorf("expected base64, got %s", v)
}
l.seenBase64Item = true
l.emit(itemBase64Enc)
}
return lexDataComma
}
func lexInParamAttr(l *lexer) stateFn {
for {
switch r := l.next(); {
case r == paramEqual:
l.backup()
return lexParamAttr
case r == dataComma:
l.backup()
return lexBase64Enc
case r == eof:
return l.errorf("unterminated parameter sequence")
case isTokenRune(r):
default:
return l.errorf("invalid character for parameter attribute")
}
}
}
func lexParamAttr(l *lexer) stateFn {
if l.pos > l.start {
l.emit(itemParamAttr)
}
return lexParamEqual
}
func lexParamEqual(l *lexer) stateFn {
l.next()
l.emit(itemParamEqual)
return lexAfterParamEqual
}
func lexAfterParamEqual(l *lexer) stateFn {
switch r := l.next(); {
case r == '"':
l.emit(itemLeftStringQuote)
return lexInQuotedStringParamVal
case r == eof:
return l.errorf("missing comma before data")
case isTokenRune(r):
return lexInParamVal
default:
return l.errorf("invalid character for parameter value")
}
}
func lexInQuotedStringParamVal(l *lexer) stateFn {
for {
switch r := l.next(); {
case r == eof:
return l.errorf("unclosed quoted string")
case r == '\\':
return lexEscapedChar
case r == '"':
l.backup()
return lexQuotedStringParamVal
case r <= unicode.MaxASCII:
default:
return l.errorf("invalid character for parameter value")
}
}
}
func lexEscapedChar(l *lexer) stateFn {
switch r := l.next(); {
case r <= unicode.MaxASCII:
return lexInQuotedStringParamVal
case r == eof:
return l.errorf("unexpected eof")
default:
return l.errorf("invalid escaped character")
}
}
func lexInParamVal(l *lexer) stateFn {
for {
switch r := l.next(); {
case r == paramSemicolon || r == dataComma:
l.backup()
return lexParamVal
case r == eof:
return l.errorf("missing comma before data")
case isTokenRune(r):
default:
return l.errorf("invalid character for parameter value")
}
}
}
func lexQuotedStringParamVal(l *lexer) stateFn {
if l.pos > l.start {
l.emit(itemParamVal)
}
l.next()
l.emit(itemRightStringQuote)
return lexAfterParamVal
}
func lexParamVal(l *lexer) stateFn {
if l.pos > l.start {
l.emit(itemParamVal)
}
return lexAfterParamVal
}
func lexAfterParamVal(l *lexer) stateFn {
switch r := l.next(); {
case r == paramSemicolon:
l.backup()
return lexParamSemicolon
case r == dataComma:
l.backup()
return lexDataComma
case r == eof:
return l.errorf("missing comma before data")
default:
return l.errorf("expected semicolon or comma")
}
}
func lexDataComma(l *lexer) stateFn {
l.next()
l.emit(itemDataComma)
if l.seenBase64Item {
return lexBase64Data
}
return lexData
}
func lexData(l *lexer) stateFn {
Loop:
for {
switch r := l.next(); {
case r == eof:
break Loop
case isURLCharRune(r):
default:
return l.errorf("invalid data character")
}
}
if l.pos > l.start {
l.emit(itemData)
}
l.emit(itemEOF)
return nil
}
func lexBase64Data(l *lexer) stateFn {
Loop:
for {
switch r := l.next(); {
case r == eof:
break Loop
case isBase64Rune(r):
default:
return l.errorf("invalid data character")
}
}
if l.pos > l.start {
l.emit(itemData)
}
l.emit(itemEOF)
return nil
}

130
vendor/github.com/vincent-petithory/dataurl/rfc2396.go generated vendored Normal file
View File

@ -0,0 +1,130 @@
package dataurl
import (
"bytes"
"fmt"
"io"
"strings"
)
// Escape implements URL escaping, as defined in RFC 2397 (http://tools.ietf.org/html/rfc2397).
// It differs a bit from net/url's QueryEscape and QueryUnescape, e.g how spaces are treated (+ instead of %20):
//
// Only ASCII chars are allowed. Reserved chars are escaped to their %xx form.
// Unreserved chars are [a-z], [A-Z], [0-9], and -_.!~*\().
func Escape(data []byte) string {
var buf = new(bytes.Buffer)
for _, b := range data {
switch {
case isUnreserved(b):
buf.WriteByte(b)
default:
fmt.Fprintf(buf, "%%%02X", b)
}
}
return buf.String()
}
// EscapeString is like Escape, but taking
// a string as argument.
func EscapeString(s string) string {
return Escape([]byte(s))
}
// isUnreserved return true
// if the byte c is an unreserved char,
// as defined in RFC 2396.
func isUnreserved(c byte) bool {
return (c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
(c >= '0' && c <= '9') ||
c == '-' ||
c == '_' ||
c == '.' ||
c == '!' ||
c == '~' ||
c == '*' ||
c == '\'' ||
c == '(' ||
c == ')'
}
func isHex(c byte) bool {
switch {
case c >= 'a' && c <= 'f':
return true
case c >= 'A' && c <= 'F':
return true
case c >= '0' && c <= '9':
return true
}
return false
}
// borrowed from net/url/url.go
func unhex(c byte) byte {
switch {
case '0' <= c && c <= '9':
return c - '0'
case 'a' <= c && c <= 'f':
return c - 'a' + 10
case 'A' <= c && c <= 'F':
return c - 'A' + 10
}
return 0
}
// Unescape unescapes a character sequence
// escaped with Escape(String?).
func Unescape(s string) ([]byte, error) {
var buf = new(bytes.Buffer)
reader := strings.NewReader(s)
for {
r, size, err := reader.ReadRune()
if err == io.EOF {
break
}
if err != nil {
return nil, err
}
if size > 1 {
return nil, fmt.Errorf("rfc2396: non-ASCII char detected")
}
switch r {
case '%':
eb1, err := reader.ReadByte()
if err == io.EOF {
return nil, fmt.Errorf("rfc2396: unexpected end of unescape sequence")
}
if err != nil {
return nil, err
}
if !isHex(eb1) {
return nil, fmt.Errorf("rfc2396: invalid char 0x%x in unescape sequence", r)
}
eb0, err := reader.ReadByte()
if err == io.EOF {
return nil, fmt.Errorf("rfc2396: unexpected end of unescape sequence")
}
if err != nil {
return nil, err
}
if !isHex(eb0) {
return nil, fmt.Errorf("rfc2396: invalid char 0x%x in unescape sequence", r)
}
buf.WriteByte(unhex(eb0) + unhex(eb1)*16)
default:
buf.WriteByte(byte(r))
}
}
return buf.Bytes(), nil
}
// UnescapeToString is like Unescape, but returning
// a string.
func UnescapeToString(s string) (string, error) {
b, err := Unescape(s)
return string(b), err
}

View File

@ -0,0 +1 @@
box: wercker/default