Files
go-i2p/lib/common/string.go

118 lines
3.2 KiB
Go
Raw Normal View History

2016-02-04 00:54:51 -08:00
package common
2016-02-15 00:34:29 -08:00
/*
2022-04-27 10:48:59 -04:00
I2P I2PString
2016-06-16 23:17:21 -07:00
https://geti2p.net/spec/common-structures#string
2016-02-15 00:34:29 -08:00
Accurate for version 0.9.24
*/
2016-02-04 00:54:51 -08:00
import (
"errors"
2022-04-27 10:48:59 -04:00
log "github.com/sirupsen/logrus"
2016-02-15 00:34:29 -08:00
)
// Maximum number of bytes that can be stored in an I2P string
2016-02-15 00:34:29 -08:00
const (
STRING_MAX_SIZE = 255
2016-02-04 00:54:51 -08:00
)
2022-04-27 10:48:59 -04:00
type I2PString []byte
2016-02-04 00:54:51 -08:00
2016-02-06 01:42:47 -08:00
//
2016-02-15 00:34:29 -08:00
// Look up the length of the string, reporting errors if the string is
// invalid or the specified length does not match the provided data.
2016-02-06 01:42:47 -08:00
//
2022-04-27 10:48:59 -04:00
func (str I2PString) Length() (length int, err error) {
if len(str) == 0 {
2016-02-15 00:34:29 -08:00
log.WithFields(log.Fields{
2022-04-27 10:48:59 -04:00
"at": "(I2PString) Length",
2016-02-15 00:34:29 -08:00
"reason": "no data",
}).Error("error parsing string")
err = errors.New("error parsing string: zero length")
return
2016-02-04 00:54:51 -08:00
}
2022-04-27 10:48:59 -04:00
l := NewInteger([]byte{byte(str[0])})
length = l.Int()
inferred_len := length + 1
str_len := len(str)
if inferred_len > str_len {
2016-02-15 00:34:29 -08:00
log.WithFields(log.Fields{
2022-04-27 10:48:59 -04:00
"at": "(I2PString) Length",
2016-02-15 00:34:29 -08:00
"string_bytes_length": str_len,
"string_length_field": length,
"expected_bytes_length": inferred_len,
"reason": "data shorter than specified",
}).Warn("string format warning")
err = errors.New("string parsing warning: string data is shorter than specified by length")
} else if str_len > inferred_len {
2016-02-15 00:34:29 -08:00
log.WithFields(log.Fields{
2022-04-27 10:48:59 -04:00
"at": "(I2PString) Length",
2016-02-15 00:34:29 -08:00
"string_bytes_length": str_len,
"string_length_field": length,
"expected_bytes_length": inferred_len,
"reason": "data longer than specified",
}).Warn("string format warning")
err = errors.New("string parsing warning: string contains data beyond length")
}
2016-02-15 00:34:29 -08:00
return
}
2016-02-06 01:42:47 -08:00
//
2016-02-15 00:34:29 -08:00
// Return the string data and any errors encountered by Length.
2016-02-06 01:42:47 -08:00
//
2022-04-27 10:48:59 -04:00
func (str I2PString) Data() (data string, err error) {
length, err := str.Length()
if err != nil {
switch err.Error() {
case "error parsing string: zero length":
2016-02-15 00:34:29 -08:00
return
case "string parsing warning: string data is shorter than specified by length":
2016-02-15 00:34:29 -08:00
data = string(str[1:])
return
case "string parsing warning: string contains data beyond length":
2016-02-15 00:34:29 -08:00
data = string(str[1 : length+1])
return
}
}
2016-02-15 00:34:29 -08:00
data = string(str[1:])
return
}
2016-02-06 01:42:47 -08:00
//
2022-04-27 10:48:59 -04:00
// This function takes an unformatted Go string and returns a I2PString
2016-02-15 00:34:29 -08:00
// and any errors encountered during the encoding.
2016-02-06 01:42:47 -08:00
//
2022-04-27 10:48:59 -04:00
func ToI2PString(data string) (str I2PString, err error) {
data_len := len(data)
if data_len > STRING_MAX_SIZE {
2016-02-15 00:34:29 -08:00
log.WithFields(log.Fields{
2022-04-27 10:48:59 -04:00
"at": "ToI2PI2PString",
2016-02-15 00:34:29 -08:00
"string_len": data_len,
"max_len": STRING_MAX_SIZE,
2016-02-15 00:34:29 -08:00
"reason": "too much data",
}).Error("cannot create I2P string")
err = errors.New("cannot store that much data in I2P string")
return
}
2016-02-05 22:35:37 -08:00
i2p_string := []byte{byte(data_len)}
i2p_string = append(i2p_string, []byte(data)...)
2022-04-27 10:48:59 -04:00
str = I2PString(i2p_string)
2016-02-15 00:34:29 -08:00
return
}
2016-02-04 00:54:51 -08:00
2016-02-06 01:42:47 -08:00
//
2016-02-15 00:34:29 -08:00
// Read a string from a slice of bytes, returning any extra data on the end
2022-04-27 10:48:59 -04:00
// of the slice and any errors encountered parsing the I2PString.
2016-02-06 01:42:47 -08:00
//
2022-04-27 10:48:59 -04:00
func ReadI2PString(data []byte) (str I2PString, remainder []byte, err error) {
str = I2PString(data)
length, err := I2PString(data).Length()
2016-02-15 00:34:29 -08:00
if err != nil && err.Error() == "string parsing warning: string contains data beyond length" {
2022-04-27 10:48:59 -04:00
str = I2PString(data[:length+1])
2016-02-15 00:34:29 -08:00
remainder = data[length+1:]
err = nil
2016-02-04 00:54:51 -08:00
}
2016-02-15 00:34:29 -08:00
return
2016-02-04 00:54:51 -08:00
}