174 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			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, &k); err != nil {
 | |
| 			return
 | |
| 		}
 | |
| 
 | |
| 		if err = binary.Write(buf, binary.BigEndian, &vLen); err != nil {
 | |
| 			return
 | |
| 		}
 | |
| 		if err = binary.Write(buf, binary.BigEndian, &v); err != nil {
 | |
| 			return
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	raw = buf.Bytes()
 | |
| 
 | |
| 	return
 | |
| }
 |