107 lines
1.9 KiB
Go
107 lines
1.9 KiB
Go
package streams
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
"unicode"
|
|
)
|
|
|
|
func quote(text string) string {
|
|
text = strings.Replace(text, "\\", "\\\\", -1)
|
|
text = strings.Replace(text, "'", "\\'", -1)
|
|
text = "'" + text + "'"
|
|
return text
|
|
}
|
|
|
|
func unquote(text string) string {
|
|
if strings.HasPrefix(text, "'") && strings.HasSuffix(text, "'") {
|
|
text = text[1 : len(text)-1]
|
|
text = strings.Replace(text, "\\'", "'", -1)
|
|
text = strings.Replace(text, "\\\\", "\\", -1)
|
|
}
|
|
return text
|
|
}
|
|
|
|
type Metadata map[string]string
|
|
|
|
func (meta Metadata) sortedKeys() []string {
|
|
keys := make([]string, len(meta))
|
|
i := 0
|
|
for key, _ := range meta {
|
|
keys[i] = key
|
|
i++
|
|
}
|
|
sort.Strings(keys)
|
|
return keys
|
|
}
|
|
|
|
func decodeMetadataItem(text string, metadata *Metadata) (err error) {
|
|
parts := strings.SplitN(text, "=", 2)
|
|
if len(parts) < 2 {
|
|
err = fmt.Errorf("expected key=value but only got key (in %q)", text)
|
|
return
|
|
}
|
|
|
|
parts[1] = unquote(parts[1])
|
|
(*metadata)[parts[0]] = parts[1]
|
|
|
|
return
|
|
}
|
|
|
|
func DecodeMetadata(source string) (meta Metadata, err error) {
|
|
// name='value'; name='value';name='value';
|
|
meta = make(Metadata)
|
|
|
|
escape := false
|
|
quoted := false
|
|
fieldsFunc := func(c rune) (retval bool) {
|
|
retval = false
|
|
if escape {
|
|
escape = false
|
|
} else {
|
|
switch {
|
|
case unicode.IsSpace(c) && !quoted:
|
|
retval = true
|
|
return
|
|
case c == '\'':
|
|
quoted = !quoted
|
|
case c == '\\' && quoted:
|
|
escape = true
|
|
case c == ';' && !quoted:
|
|
retval = true
|
|
return
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
for _, field := range strings.FieldsFunc(source, fieldsFunc) {
|
|
if len(field) == 0 {
|
|
continue
|
|
}
|
|
if err = decodeMetadataItem(field, &meta); err != nil {
|
|
return
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (meta Metadata) String() string {
|
|
mstr := ""
|
|
|
|
if meta != nil {
|
|
for _, key := range meta.sortedKeys() {
|
|
value := meta[key]
|
|
mstr += fmt.Sprintf("%s=%s;", key, quote(value))
|
|
}
|
|
}
|
|
|
|
return mstr
|
|
}
|
|
|
|
func (meta Metadata) Bytes() (buf []byte) {
|
|
return []byte(meta.String())
|
|
}
|