diff options
author | Laria Carolin Chabowski <laria@laria.me> | 2017-06-25 21:49:04 +0200 |
---|---|---|
committer | Laria Carolin Chabowski <laria@laria.me> | 2017-06-25 21:49:04 +0200 |
commit | f98b4e4b8165497b64d28d3e54babd1a43ad46d6 (patch) | |
tree | 56f6a34122d46a210d975849c7c599adb924f820 /objects/properties.go | |
parent | 1d21280ec755525c6158cd18d01ec4e9ca73d7a0 (diff) | |
download | petrific-f98b4e4b8165497b64d28d3e54babd1a43ad46d6.tar.gz petrific-f98b4e4b8165497b64d28d3e54babd1a43ad46d6.tar.bz2 petrific-f98b4e4b8165497b64d28d3e54babd1a43ad46d6.zip |
File and Blob objects
Diffstat (limited to 'objects/properties.go')
-rw-r--r-- | objects/properties.go | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/objects/properties.go b/objects/properties.go new file mode 100644 index 0000000..6b4acc1 --- /dev/null +++ b/objects/properties.go @@ -0,0 +1,93 @@ +package objects + +import ( + "encoding/hex" + "fmt" + "net/url" + "sort" +) + +// properties are mappings from strings to strings that are encoded as a restricted version of URL query strings +// (only the characters [a-zA-Z0-9.:_-] are allowed, values are ordered by their key) +type properties map[string]string + +// escapePropertyString escapes all bytes not in [a-zA-Z0-9.:_-] as %XX, where XX represents the hexadecimal value of the byte. +// Compatible with URL query strings +func escapePropertyString(s string) []byte { + out := []byte{} + esc := []byte("%XX") + + for _, b := range []byte(s) { + if (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || (b >= '0' && b <= '9') || b == '.' || b == ':' || b == '_' || b == '-' { + out = append(out, b) + } else { + hex.Encode(esc[1:], []byte{b}) + out = append(out, esc...) + } + } + + return out +} + +func (p properties) MarshalText() ([]byte, error) { // Guaranteed to not fail, error is only here to satisfy encoding.TextMarshaler + keys := make([]string, len(p)) + i := 0 + for k := range p { + keys[i] = k + i++ + } + + sort.Strings(keys) + + out := []byte{} + + first := true + for _, k := range keys { + if first { + first = false + } else { + out = append(out, '&') + } + + out = append(out, escapePropertyString(k)...) + out = append(out, '=') + out = append(out, escapePropertyString(p[k])...) + } + + return out, nil +} + +func (p properties) UnmarshalText(text []byte) error { + vals, err := url.ParseQuery(string(text)) + if err != nil { + return err + } + + for k, v := range vals { + if len(v) != 1 { + return fmt.Errorf("Got %d values for key %s, expected 1", len(v), k) + } + + p[k] = v[0] + } + + return nil +} + +func (a properties) Equals(b properties) bool { + for k, va := range a { + vb, ok := b[k] + if !ok || vb != va { + return false + } + } + + for k := range b { + _, ok := a[k] + if !ok { + return false + } + } + + return true +} |