aboutsummaryrefslogtreecommitdiffstats
path: root/common/infostring
diff options
context:
space:
mode:
authorGravatar BanceDev 2026-02-16 16:31:54 -0500
committerGravatar BanceDev 2026-02-16 16:31:54 -0500
commitca90ebdfa8789654766c5d7969baa7afacd9ebd2 (patch)
tree9693e0c7a5af6713f4c5e39372dcf22d05844ec3 /common/infostring
initial commitHEADmain
Diffstat (limited to 'common/infostring')
-rw-r--r--common/infostring/infostring.go72
-rw-r--r--common/infostring/infostring_test.go49
-rw-r--r--common/infostring/option.go9
3 files changed, 130 insertions, 0 deletions
diff --git a/common/infostring/infostring.go b/common/infostring/infostring.go
new file mode 100644
index 0000000..114058a
--- /dev/null
+++ b/common/infostring/infostring.go
@@ -0,0 +1,72 @@
+package infostring
+
+import (
+ "strings"
+
+ "github.com/osm/quake/common/buffer"
+)
+
+type InfoString struct {
+ Info []Info
+}
+
+type Info struct {
+ Key string
+ Value string
+}
+
+func New(opts ...Option) *InfoString {
+ var infoString InfoString
+
+ for _, opt := range opts {
+ opt(&infoString)
+ }
+
+ return &infoString
+}
+
+func (is *InfoString) Bytes() []byte {
+ buf := buffer.New()
+
+ buf.PutByte(byte('"'))
+
+ for i := 0; i < len(is.Info); i++ {
+ buf.PutBytes([]byte("\\" + is.Info[i].Key))
+ buf.PutBytes([]byte("\\" + is.Info[i].Value))
+ }
+
+ buf.PutByte(byte('"'))
+
+ return buf.Bytes()
+}
+
+func Parse(input string) *InfoString {
+ var ret InfoString
+
+ trimmed := strings.Trim(input, "\"")
+ parts := strings.Split(trimmed, "\\")
+
+ for i := 1; i < len(parts)-1; i += 2 {
+ ret.Info = append(ret.Info, Info{parts[i], parts[i+1]})
+ }
+
+ return &ret
+}
+
+func (is *InfoString) Get(key string) string {
+ for i := 0; i < len(is.Info); i++ {
+ if is.Info[i].Key == key {
+ return is.Info[i].Value
+ }
+ }
+
+ return ""
+}
+
+func (is *InfoString) Set(key, value string) {
+ for i := 0; i < len(is.Info); i++ {
+ if is.Info[i].Key == key {
+ is.Info[i].Value = value
+ }
+ }
+}
diff --git a/common/infostring/infostring_test.go b/common/infostring/infostring_test.go
new file mode 100644
index 0000000..977090d
--- /dev/null
+++ b/common/infostring/infostring_test.go
@@ -0,0 +1,49 @@
+package infostring
+
+import (
+ "reflect"
+ "testing"
+)
+
+type infoStringTest struct {
+ name string
+ input string
+ expected InfoString
+}
+
+var infoStringTests = []infoStringTest{
+ {
+ name: "foo",
+ input: "\"\\FOO\\foo\\BAR\\bar\\BAZ\\baz\"",
+ expected: InfoString{
+ Info: []Info{
+ Info{Key: "FOO", Value: "foo"},
+ Info{Key: "BAR", Value: "bar"},
+ Info{Key: "BAZ", Value: "baz"},
+ },
+ },
+ },
+ {
+ name: "\\foo\\with spaces",
+ input: "\"\\foo\\with spaces\"",
+ expected: InfoString{
+ Info: []Info{
+ Info{Key: "foo", Value: "with spaces"},
+ },
+ },
+ },
+}
+
+func TestInfoString(t *testing.T) {
+ for _, is := range infoStringTests {
+ t.Run(is.name, func(t *testing.T) {
+ infoString := Parse(is.input)
+
+ if !reflect.DeepEqual(is.expected.Bytes(), infoString.Bytes()) {
+ t.Errorf("parsed infostring output didn't match")
+ t.Logf("output: %#v\n", infoString)
+ t.Logf("expected: %#v\n", is.expected)
+ }
+ })
+ }
+}
diff --git a/common/infostring/option.go b/common/infostring/option.go
new file mode 100644
index 0000000..f64fefa
--- /dev/null
+++ b/common/infostring/option.go
@@ -0,0 +1,9 @@
+package infostring
+
+type Option func(*InfoString)
+
+func WithKeyValue(key, value string) Option {
+ return func(is *InfoString) {
+ is.Info = append(is.Info, Info{key, value})
+ }
+}