gokwallet/utils.go

174 lines
3.7 KiB
Go

package gokwallet
import (
"bytes"
"encoding/binary"
"strings"
"github.com/godbus/dbus/v5"
)
/*
resultCheck checks the result code from a Dbus call and returns an error if not successful.
See also resultPassed.
*/
func resultCheck(result int32) (err error) {
// This is technically way more complex than it needs to be, but is extendable for future use.
switch i := result; i {
case DbusSuccess:
err = nil
case DbusFailure:
err = ErrOperationFailed
default:
err = ErrOperationFailed
}
return
}
/*
resultPassed checks the result code from a Dbus call and returns a boolean as to whether the result is pass or not.
See also resultCheck.
*/
func resultPassed(result int32) (passed bool) {
// This is technically way more complex than it needs to be, but is extendable for future use.
switch i := result; i {
case DbusSuccess:
passed = true
case DbusFailure:
passed = false
default:
passed = false
}
return
}
// bytemapKeys is used to parse out Map names when fetching from Dbus.
func bytemapKeys(variant dbus.Variant) (keyNames []string) {
var d map[string]dbus.Variant
d = variant.Value().(map[string]dbus.Variant)
keyNames = make([]string, len(d))
idx := 0
for k, _ := range d {
keyNames[idx] = k
idx++
}
return
}
// bytesToMap takes a byte slice and returns a map[string]string based on a Dbus QMap struct(ure).
func bytesToMap(raw []byte) (m map[string]string, numEntries uint32, err error) {
var buf *bytes.Reader
var kLen uint32
var vLen uint32
var k []byte
var v []byte
/*
I considered using:
- https://github.com/lunixbochs/struc
- https://github.com/roman-kachanovsky/go-binary-pack
- https://github.com/go-restruct/restruct
The second hasn't been updated in quite some time, the first or third would have been a headache due to the variable length,
and ultimately I felt it was silly to add a dependency for only a single piece of data (Map).
So sticking to stdlib.
*/
buf = bytes.NewReader(raw)
if err = binary.Read(buf, binary.BigEndian, &numEntries); err != nil {
return
}
m = make(map[string]string, numEntries)
for i := uint32(0); i < numEntries; i++ {
if err = binary.Read(buf, binary.BigEndian, &kLen); err != nil {
return
}
k = make([]byte, kLen)
if err = binary.Read(buf, binary.BigEndian, &k); err != nil {
return
}
if err = binary.Read(buf, binary.BigEndian, &vLen); err != nil {
return
}
v = make([]byte, vLen)
if err = binary.Read(buf, binary.BigEndian, &v); err != nil {
return
}
// QMap does this infuriating thing where it separates each character with a null byte. So we need to strip them out.
k = bytes.ReplaceAll(k, []byte{0x0}, []byte{})
v = bytes.ReplaceAll(v, []byte{0x0}, []byte{})
m[string(k)] = string(v)
}
return
}
// mapToBytes performs the inverse of bytesToMap.
func mapToBytes(m map[string]string) (raw []byte, err error) {
var numEntries uint32
var buf *bytes.Buffer
var kLen uint32
var vLen uint32
var kB []byte
var vB []byte
if m == nil {
err = ErrInvalidMap
return
}
numEntries = uint32(len(m))
buf = &bytes.Buffer{}
if err = binary.Write(buf, binary.BigEndian, &numEntries); err != nil {
return
}
for k, v := range m {
kB = []byte(strings.Join(strings.Split(k, ""), "\x00"))
vB = []byte(strings.Join(strings.Split(v, ""), "\x00"))
kLen = uint32(len(kB))
vLen = uint32(len(vB))
if err = binary.Write(buf, binary.BigEndian, &kLen); err != nil {
return
}
if err = binary.Write(buf, binary.BigEndian, &kB); err != nil {
return
}
if err = binary.Write(buf, binary.BigEndian, &vLen); err != nil {
return
}
if err = binary.Write(buf, binary.BigEndian, &vB); err != nil {
return
}
}
raw = buf.Bytes()
return
}