mirror of
https://github.com/Luzifer/sii.git
synced 2024-10-18 05:14:19 +00:00
Add writing of unit files
Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
parent
426e54f372
commit
ccb5be1dbe
11 changed files with 457 additions and 179 deletions
|
@ -11,7 +11,7 @@ type Company struct {
|
|||
JobOffer []Ptr `sii:"job_offer"`
|
||||
CargoOfferSeeds []int64 `sii:"cargo_offer_seeds"`
|
||||
Discovered bool `sii:"discovered"`
|
||||
ReservedTrailerSlot int64 `sii:"reserved_trailer_slot"` // TODO: Maybe wrong type, haven't seen other than "nil"
|
||||
ReservedTrailerSlot Ptr `sii:"reserved_trailer_slot"` // TODO: Maybe wrong type, haven't seen other than "nil"
|
||||
|
||||
blockName string
|
||||
}
|
||||
|
|
|
@ -5,19 +5,19 @@ func init() {
|
|||
}
|
||||
|
||||
type JobOfferData struct {
|
||||
Target string `sii:"target"`
|
||||
ExpirationTime int64 `sii:"expiration_time"`
|
||||
Urgency int64 `sii:"urgency"`
|
||||
ShortestDistanceKM int64 `sii:"shortest_distance_km"`
|
||||
FerryTime int64 `sii:"ferry_time"`
|
||||
FerryPrice int64 `sii:"ferry_price"`
|
||||
Cargo Ptr `sii:"cargo"` // External pointer
|
||||
CompanyTruck Ptr `sii:"company_truck"` // Partial external pointer?
|
||||
TrailerVariant Ptr `sii:"trailer_variant"` // External pointer
|
||||
TrailerDefinition Ptr `sii:"trailer_definition"` // External pointer
|
||||
UnitsCount int64 `sii:"units_count"`
|
||||
FillRatio float32 `sii:"fill_ratio"`
|
||||
TrailerPlace int64 `sii:"trailer_place"` // TODO: What's this? Seems to be "0" in all jobs
|
||||
Target string `sii:"target"`
|
||||
ExpirationTime *int64 `sii:"expiration_time"`
|
||||
Urgency *int64 `sii:"urgency"`
|
||||
ShortestDistanceKM int64 `sii:"shortest_distance_km"`
|
||||
FerryTime int64 `sii:"ferry_time"`
|
||||
FerryPrice int64 `sii:"ferry_price"`
|
||||
Cargo Ptr `sii:"cargo"` // External pointer
|
||||
CompanyTruck Ptr `sii:"company_truck"` // Partial external pointer?
|
||||
TrailerVariant Ptr `sii:"trailer_variant"` // External pointer
|
||||
TrailerDefinition Ptr `sii:"trailer_definition"` // External pointer
|
||||
UnitsCount int64 `sii:"units_count"`
|
||||
FillRatio float32 `sii:"fill_ratio"`
|
||||
TrailerPlace []Placement `sii:"trailer_place"`
|
||||
|
||||
blockName string
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ func init() {
|
|||
}
|
||||
|
||||
type Player struct {
|
||||
HQCity string `sii:"hq_city"`
|
||||
HQCity Ptr `sii:"hq_city"`
|
||||
Trailers []Ptr `sii:"trailers"`
|
||||
TrailerUtilizationLogs []Ptr `sii:"trailer_utilization_logs"`
|
||||
TrailerDefs []Ptr `sii:"trailer_defs"`
|
||||
|
|
10
datatypes.go
10
datatypes.go
|
@ -21,24 +21,24 @@ var placementRegexp = regexp.MustCompile(`^\(([0-9.]+|&[0-9a-f]+), ([0-9.]+|&[0-
|
|||
type Placement [7]float32
|
||||
|
||||
func (p Placement) MarshalSII() ([]byte, error) {
|
||||
var siiFloats = [][]byte{}
|
||||
var siiFloats = make([][]byte, 7)
|
||||
|
||||
for _, f := range p {
|
||||
for i, f := range p {
|
||||
b, err := float2sii(f)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Unable to encode float")
|
||||
}
|
||||
siiFloats = append(siiFloats, b)
|
||||
siiFloats[i] = b
|
||||
}
|
||||
|
||||
var buf = new(bytes.Buffer)
|
||||
|
||||
buf.Write([]byte("("))
|
||||
bytes.Join(siiFloats[0:3], []byte(", "))
|
||||
buf.Write(bytes.Join(siiFloats[0:3], []byte(", ")))
|
||||
buf.Write([]byte(") ("))
|
||||
buf.Write(siiFloats[3])
|
||||
buf.Write([]byte("; "))
|
||||
bytes.Join(siiFloats[4:7], []byte(", "))
|
||||
buf.Write(bytes.Join(siiFloats[4:7], []byte(", ")))
|
||||
buf.Write([]byte(")"))
|
||||
|
||||
return buf.Bytes(), nil
|
||||
|
|
59
generator.go
Normal file
59
generator.go
Normal file
|
@ -0,0 +1,59 @@
|
|||
package sii
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func writeSIIPlainFile(unit *Unit, w io.Writer) error {
|
||||
var err error
|
||||
|
||||
// Write file header
|
||||
if _, err = fmt.Fprintln(w, "SiiNunit\n{"); err != nil {
|
||||
return errors.Wrap(err, "Unable to write header")
|
||||
}
|
||||
|
||||
for _, block := range unit.Entries {
|
||||
// Write block header
|
||||
if _, err = fmt.Fprintf(w, "%s : %s {\n", block.Class(), block.Name()); err != nil {
|
||||
return errors.Wrap(err, "Unable to write block header")
|
||||
}
|
||||
|
||||
// Obtain and write block content
|
||||
var raw []byte
|
||||
|
||||
if reflect.TypeOf(block).Elem().Implements(reflect.TypeOf((*Marshaler)(nil)).Elem()) {
|
||||
raw, err = block.(Marshaler).MarshalSII()
|
||||
} else {
|
||||
raw, err = genericMarshal(block)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Unable to marshal block")
|
||||
}
|
||||
|
||||
if len(raw) > 0 {
|
||||
raw = append(bytes.TrimRight(raw, "\n"), '\n')
|
||||
}
|
||||
|
||||
if _, err = w.Write(raw); err != nil {
|
||||
return errors.Wrap(err, "Unable to write block data")
|
||||
}
|
||||
|
||||
// Close block
|
||||
if _, err = fmt.Fprintf(w, "}\n\n"); err != nil {
|
||||
return errors.Wrap(err, "Unable to close block")
|
||||
}
|
||||
}
|
||||
|
||||
// Write file footer
|
||||
if _, err = fmt.Fprintln(w, "}"); err != nil {
|
||||
return errors.Wrap(err, "Unable to write footer")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -1,36 +1,26 @@
|
|||
package sii
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
singleLineValue = `^\s*%s\s?:\s?(.+)$`
|
||||
arrayLineValue = `^\s*%s(\[([0-9]*)\])?\s?:\s?(.+)$`
|
||||
)
|
||||
|
||||
func genericMarshal(in interface{}) ([]byte, error) {
|
||||
return nil, errors.New("Not implemented")
|
||||
}
|
||||
|
||||
func genericUnmarshal(in []byte, out interface{}, unit *Unit) error {
|
||||
if reflect.TypeOf(out).Kind() != reflect.Ptr {
|
||||
return errors.New("Calling parser with non-pointer")
|
||||
if reflect.TypeOf(in).Kind() == reflect.Ptr {
|
||||
in = reflect.ValueOf(in).Elem().Interface()
|
||||
}
|
||||
|
||||
if reflect.ValueOf(out).Elem().Kind() != reflect.Struct {
|
||||
return errors.New("Calling parser with pointer to non-struct")
|
||||
if reflect.TypeOf(in).Kind() != reflect.Struct {
|
||||
return nil, errors.New("Calling marshaller with non-struct")
|
||||
}
|
||||
|
||||
st := reflect.ValueOf(out).Elem()
|
||||
var buf = new(bytes.Buffer)
|
||||
|
||||
st := reflect.ValueOf(in)
|
||||
for i := 0; i < st.NumField(); i++ {
|
||||
valField := st.Field(i)
|
||||
typeField := st.Type().Field(i)
|
||||
|
@ -44,208 +34,146 @@ func genericUnmarshal(in []byte, out interface{}, unit *Unit) error {
|
|||
switch typeField.Type {
|
||||
|
||||
case reflect.TypeOf(Ptr{}):
|
||||
data := getSingleValue(in, attributeName)
|
||||
v := Ptr{unit: unit}
|
||||
if err := v.UnmarshalSII(data); err != nil {
|
||||
return errors.Wrapf(err, "Unable to parse Ptr for attribute %q", attributeName)
|
||||
}
|
||||
valField.Set(reflect.ValueOf(v))
|
||||
v := valField.Interface().(Ptr).MarshalSII()
|
||||
buf.WriteString(fmt.Sprintf(" %s: %s\n", attributeName, v))
|
||||
continue
|
||||
|
||||
case reflect.TypeOf(Placement{}):
|
||||
data := getSingleValue(in, attributeName)
|
||||
v := Placement{}
|
||||
if err := v.UnmarshalSII(data); err != nil {
|
||||
return errors.Wrapf(err, "Unable to parse Placement for attribute %q", attributeName)
|
||||
v, err := valField.Interface().(Placement).MarshalSII()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Unable to encode Placement")
|
||||
}
|
||||
valField.Set(reflect.ValueOf(v))
|
||||
buf.WriteString(fmt.Sprintf(" %s: %s\n", attributeName, v))
|
||||
continue
|
||||
|
||||
}
|
||||
|
||||
switch typeField.Type.Kind() {
|
||||
|
||||
case reflect.Bool:
|
||||
v, err := strconv.ParseBool(string(getSingleValue(in, attributeName)))
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Unable to parse boolean for attribute %q", attributeName)
|
||||
}
|
||||
valField.SetBool(v)
|
||||
v := valField.Bool()
|
||||
buf.WriteString(fmt.Sprintf(" %s: %s\n", attributeName, strconv.FormatBool(v)))
|
||||
|
||||
case reflect.Float32:
|
||||
v, err := sii2float(getSingleValue(in, attributeName))
|
||||
v, err := float2sii(float32(valField.Float()))
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Unable to parse float for attribute %q", attributeName)
|
||||
return nil, errors.Wrap(err, "Unable to encode float32")
|
||||
}
|
||||
valField.Set(reflect.ValueOf(v))
|
||||
buf.WriteString(fmt.Sprintf(" %s: %s\n", attributeName, v))
|
||||
|
||||
case reflect.Int, reflect.Int64:
|
||||
bv := getSingleValue(in, attributeName)
|
||||
if isNilValue(bv) {
|
||||
continue
|
||||
}
|
||||
v, err := strconv.ParseInt(string(bv), 10, 64)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Unable to parse int for attribute %q", attributeName)
|
||||
}
|
||||
valField.SetInt(v)
|
||||
buf.WriteString(fmt.Sprintf(" %s: %d\n", attributeName, valField.Int()))
|
||||
|
||||
case reflect.String:
|
||||
v := strings.Trim(string(getSingleValue(in, attributeName)), `"`)
|
||||
valField.SetString(v)
|
||||
buf.WriteString(fmt.Sprintf(" %s: %q\n", attributeName, valField.String()))
|
||||
|
||||
case reflect.Uint64:
|
||||
v, err := strconv.ParseUint(string(getSingleValue(in, attributeName)), 10, 64)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Unable to parse uint for attribute %q", attributeName)
|
||||
v := strconv.FormatUint(valField.Uint(), 10)
|
||||
buf.WriteString(fmt.Sprintf(" %s: %s\n", attributeName, v))
|
||||
|
||||
case reflect.Ptr:
|
||||
|
||||
switch typeField.Type.Elem().Kind() {
|
||||
|
||||
case reflect.Int64:
|
||||
var v string
|
||||
if valField.IsNil() {
|
||||
v = "nil"
|
||||
} else {
|
||||
v = strconv.FormatInt(valField.Elem().Int(), 10)
|
||||
}
|
||||
buf.WriteString(fmt.Sprintf(" %s: %s\n", attributeName, v))
|
||||
|
||||
default:
|
||||
return nil, errors.Errorf("Unsupported type: *%s", typeField.Type.Elem().Kind())
|
||||
|
||||
}
|
||||
valField.SetUint(v)
|
||||
|
||||
case reflect.Slice:
|
||||
ba, err := getArrayValues(in, attributeName)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Unable to fetch array values for attribute %q", attributeName)
|
||||
}
|
||||
var values []string
|
||||
|
||||
switch typeField.Type.Elem() {
|
||||
|
||||
case reflect.TypeOf(Ptr{}):
|
||||
var v []Ptr
|
||||
for _, bv := range ba {
|
||||
e := Ptr{unit: unit}
|
||||
if err := e.UnmarshalSII(bv); err != nil {
|
||||
return errors.Wrapf(err, "Unable to parse Ptr for attribute %q", attributeName)
|
||||
}
|
||||
v = append(v, e)
|
||||
for _, val := range valField.Interface().([]Ptr) {
|
||||
values = append(values, string(val.MarshalSII()))
|
||||
}
|
||||
valField.Set(reflect.ValueOf(v))
|
||||
buf.Write(encodeSliceValue(attributeName, values))
|
||||
continue
|
||||
|
||||
case reflect.TypeOf(Placement{}):
|
||||
var v []Placement
|
||||
for _, bv := range ba {
|
||||
e := Placement{}
|
||||
if err := e.UnmarshalSII(bv); err != nil {
|
||||
return errors.Wrapf(err, "Unable to parse Placement for attribute %q", attributeName)
|
||||
for _, val := range valField.Interface().([]Placement) {
|
||||
ev, err := val.MarshalSII()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Unable to encode Placement")
|
||||
}
|
||||
v = append(v, e)
|
||||
values = append(values, string(ev))
|
||||
}
|
||||
valField.Set(reflect.ValueOf(v))
|
||||
buf.Write(encodeSliceValue(attributeName, values))
|
||||
continue
|
||||
|
||||
case reflect.TypeOf(RawValue{}):
|
||||
var v []RawValue
|
||||
for _, bv := range ba {
|
||||
e := RawValue{}
|
||||
if err := e.UnmarshalSII(bv); err != nil {
|
||||
return errors.Wrapf(err, "Unable to parse RawValue for attribute %q", attributeName)
|
||||
for _, val := range valField.Interface().([]RawValue) {
|
||||
ev, err := val.MarshalSII()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Unable to encode RawValue")
|
||||
}
|
||||
v = append(v, e)
|
||||
values = append(values, string(ev))
|
||||
}
|
||||
valField.Set(reflect.ValueOf(v))
|
||||
buf.Write(encodeSliceValue(attributeName, values))
|
||||
continue
|
||||
|
||||
}
|
||||
|
||||
switch typeField.Type.Elem().Kind() {
|
||||
|
||||
case reflect.Bool:
|
||||
var v []bool
|
||||
for _, bv := range ba {
|
||||
pbv, err := strconv.ParseBool(string(bv))
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Unable to parse boolean for attribute %q", attributeName)
|
||||
}
|
||||
v = append(v, pbv)
|
||||
for _, val := range valField.Interface().([]bool) {
|
||||
values = append(values, strconv.FormatBool(val))
|
||||
}
|
||||
valField.Set(reflect.ValueOf(v))
|
||||
buf.Write(encodeSliceValue(attributeName, values))
|
||||
|
||||
case reflect.Int:
|
||||
var v []int
|
||||
for _, bv := range ba {
|
||||
pbv, err := strconv.Atoi(string(bv))
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Unable to parse int for attribute %q", attributeName)
|
||||
}
|
||||
v = append(v, pbv)
|
||||
for _, val := range valField.Interface().([]int) {
|
||||
values = append(values, strconv.FormatInt(int64(val), 10))
|
||||
}
|
||||
valField.Set(reflect.ValueOf(v))
|
||||
buf.Write(encodeSliceValue(attributeName, values))
|
||||
|
||||
case reflect.Int64:
|
||||
var v []int64
|
||||
for _, bv := range ba {
|
||||
pbv, err := strconv.ParseInt(string(bv), 10, 64)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Unable to parse int for attribute %q", attributeName)
|
||||
}
|
||||
v = append(v, pbv)
|
||||
for _, val := range valField.Interface().([]int64) {
|
||||
values = append(values, strconv.FormatInt(val, 10))
|
||||
}
|
||||
valField.Set(reflect.ValueOf(v))
|
||||
buf.Write(encodeSliceValue(attributeName, values))
|
||||
|
||||
case reflect.String:
|
||||
var v []string
|
||||
for _, bv := range ba {
|
||||
v = append(v, strings.Trim(string(bv), `"`))
|
||||
for _, val := range valField.Interface().([]string) {
|
||||
values = append(values, val)
|
||||
}
|
||||
valField.Set(reflect.ValueOf(v))
|
||||
buf.Write(encodeSliceValue(attributeName, values))
|
||||
|
||||
default:
|
||||
return errors.Errorf("Unsupported type: []%s", typeField.Type.Elem().Kind())
|
||||
return nil, errors.Errorf("Unsupported type: []%s", typeField.Type.Elem().Kind())
|
||||
|
||||
}
|
||||
|
||||
default:
|
||||
return errors.Errorf("Unsupported type: %s", typeField.Type.Kind())
|
||||
return nil, errors.Errorf("Unsupported type: %s", typeField.Type.Kind())
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func getSingleValue(in []byte, name string) []byte {
|
||||
rex := regexp.MustCompile(fmt.Sprintf(singleLineValue, name))
|
||||
func encodeSliceValue(attributeName string, values []string) []byte {
|
||||
var buf = new(bytes.Buffer)
|
||||
|
||||
var scanner = bufio.NewScanner(bytes.NewReader(in))
|
||||
for scanner.Scan() {
|
||||
if rex.Match(scanner.Bytes()) {
|
||||
grp := rex.FindSubmatch(scanner.Bytes())
|
||||
return grp[1]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
fmt.Fprintf(buf, " %s: %d\n", attributeName, len(values))
|
||||
|
||||
func getArrayValues(in []byte, name string) ([][]byte, error) {
|
||||
rex := regexp.MustCompile(fmt.Sprintf(arrayLineValue, name))
|
||||
var out [][]byte
|
||||
|
||||
var scanner = bufio.NewScanner(bytes.NewReader(in))
|
||||
for scanner.Scan() {
|
||||
if rex.Match(scanner.Bytes()) {
|
||||
grp := rex.FindSubmatch(scanner.Bytes())
|
||||
if len(grp[1]) == 0 {
|
||||
arrayLen, err := strconv.Atoi(string(grp[3]))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Unable to parse array capacity")
|
||||
}
|
||||
out = make([][]byte, arrayLen)
|
||||
continue
|
||||
}
|
||||
|
||||
if len(grp[2]) == 0 {
|
||||
out = append(out, grp[3])
|
||||
continue
|
||||
}
|
||||
|
||||
idx, err := strconv.Atoi(string(grp[2]))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Unable to parse array index")
|
||||
}
|
||||
|
||||
out[idx] = grp[3]
|
||||
}
|
||||
for i, v := range values {
|
||||
fmt.Fprintf(buf, " %s[%d]: %s\n", attributeName, i, v)
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func isNilValue(in []byte) bool {
|
||||
return reflect.DeepEqual(in, []byte("nil"))
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
|
270
genericUnmarshaller.go
Normal file
270
genericUnmarshaller.go
Normal file
|
@ -0,0 +1,270 @@
|
|||
package sii
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
singleLineValue = `^\s*%s\s?:\s?(.+)$`
|
||||
arrayLineValue = `^\s*%s(\[([0-9]*)\])?\s?:\s?(.+)$`
|
||||
)
|
||||
|
||||
func genericUnmarshal(in []byte, out interface{}, unit *Unit) error {
|
||||
if reflect.TypeOf(out).Kind() != reflect.Ptr {
|
||||
return errors.New("Calling parser with non-pointer")
|
||||
}
|
||||
|
||||
if reflect.ValueOf(out).Elem().Kind() != reflect.Struct {
|
||||
return errors.New("Calling parser with pointer to non-struct")
|
||||
}
|
||||
|
||||
st := reflect.ValueOf(out).Elem()
|
||||
for i := 0; i < st.NumField(); i++ {
|
||||
valField := st.Field(i)
|
||||
typeField := st.Type().Field(i)
|
||||
|
||||
attributeName := typeField.Tag.Get("sii")
|
||||
if attributeName == "" {
|
||||
// Names must be explicitly defined, library does not support name guessing
|
||||
continue
|
||||
}
|
||||
|
||||
switch typeField.Type {
|
||||
|
||||
case reflect.TypeOf(Ptr{}):
|
||||
data := getSingleValue(in, attributeName)
|
||||
v := Ptr{unit: unit}
|
||||
if err := v.UnmarshalSII(data); err != nil {
|
||||
return errors.Wrapf(err, "Unable to parse Ptr for attribute %q", attributeName)
|
||||
}
|
||||
valField.Set(reflect.ValueOf(v))
|
||||
continue
|
||||
|
||||
case reflect.TypeOf(Placement{}):
|
||||
data := getSingleValue(in, attributeName)
|
||||
v := Placement{}
|
||||
if err := v.UnmarshalSII(data); err != nil {
|
||||
return errors.Wrapf(err, "Unable to parse Placement for attribute %q", attributeName)
|
||||
}
|
||||
valField.Set(reflect.ValueOf(v))
|
||||
continue
|
||||
|
||||
}
|
||||
|
||||
switch typeField.Type.Kind() {
|
||||
case reflect.Bool:
|
||||
v, err := strconv.ParseBool(string(getSingleValue(in, attributeName)))
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Unable to parse boolean for attribute %q", attributeName)
|
||||
}
|
||||
valField.SetBool(v)
|
||||
|
||||
case reflect.Float32:
|
||||
v, err := sii2float(getSingleValue(in, attributeName))
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Unable to parse float for attribute %q", attributeName)
|
||||
}
|
||||
valField.Set(reflect.ValueOf(v))
|
||||
|
||||
case reflect.Int, reflect.Int64:
|
||||
bv := getSingleValue(in, attributeName)
|
||||
if isNilValue(bv) {
|
||||
continue
|
||||
}
|
||||
v, err := strconv.ParseInt(string(bv), 10, 64)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Unable to parse int for attribute %q", attributeName)
|
||||
}
|
||||
valField.SetInt(v)
|
||||
|
||||
case reflect.String:
|
||||
v := strings.Trim(string(getSingleValue(in, attributeName)), `"`)
|
||||
valField.SetString(v)
|
||||
|
||||
case reflect.Uint64:
|
||||
v, err := strconv.ParseUint(string(getSingleValue(in, attributeName)), 10, 64)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Unable to parse uint for attribute %q", attributeName)
|
||||
}
|
||||
valField.SetUint(v)
|
||||
|
||||
case reflect.Ptr:
|
||||
|
||||
switch typeField.Type.Elem().Kind() {
|
||||
|
||||
case reflect.Int64:
|
||||
bv := getSingleValue(in, attributeName)
|
||||
if !isNilValue(bv) {
|
||||
v, err := strconv.ParseInt(string(bv), 10, 64)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Unable to parse int for attribute %q", attributeName)
|
||||
}
|
||||
valField.Set(reflect.ValueOf(&v))
|
||||
}
|
||||
|
||||
default:
|
||||
return errors.Errorf("Unsupported type: *%s", typeField.Type.Elem().Kind())
|
||||
|
||||
}
|
||||
|
||||
case reflect.Slice:
|
||||
ba, err := getArrayValues(in, attributeName)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Unable to fetch array values for attribute %q", attributeName)
|
||||
}
|
||||
|
||||
switch typeField.Type.Elem() {
|
||||
|
||||
case reflect.TypeOf(Ptr{}):
|
||||
var v []Ptr
|
||||
for _, bv := range ba {
|
||||
e := Ptr{unit: unit}
|
||||
if err := e.UnmarshalSII(bv); err != nil {
|
||||
return errors.Wrapf(err, "Unable to parse Ptr for attribute %q", attributeName)
|
||||
}
|
||||
v = append(v, e)
|
||||
}
|
||||
valField.Set(reflect.ValueOf(v))
|
||||
continue
|
||||
|
||||
case reflect.TypeOf(Placement{}):
|
||||
var v []Placement
|
||||
for _, bv := range ba {
|
||||
e := Placement{}
|
||||
if err := e.UnmarshalSII(bv); err != nil {
|
||||
return errors.Wrapf(err, "Unable to parse Placement for attribute %q", attributeName)
|
||||
}
|
||||
v = append(v, e)
|
||||
}
|
||||
valField.Set(reflect.ValueOf(v))
|
||||
continue
|
||||
|
||||
case reflect.TypeOf(RawValue{}):
|
||||
var v []RawValue
|
||||
for _, bv := range ba {
|
||||
e := RawValue{}
|
||||
if err := e.UnmarshalSII(bv); err != nil {
|
||||
return errors.Wrapf(err, "Unable to parse RawValue for attribute %q", attributeName)
|
||||
}
|
||||
v = append(v, e)
|
||||
}
|
||||
valField.Set(reflect.ValueOf(v))
|
||||
continue
|
||||
|
||||
}
|
||||
|
||||
switch typeField.Type.Elem().Kind() {
|
||||
case reflect.Bool:
|
||||
var v []bool
|
||||
for _, bv := range ba {
|
||||
pbv, err := strconv.ParseBool(string(bv))
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Unable to parse boolean for attribute %q", attributeName)
|
||||
}
|
||||
v = append(v, pbv)
|
||||
}
|
||||
valField.Set(reflect.ValueOf(v))
|
||||
|
||||
case reflect.Int:
|
||||
var v []int
|
||||
for _, bv := range ba {
|
||||
pbv, err := strconv.Atoi(string(bv))
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Unable to parse int for attribute %q", attributeName)
|
||||
}
|
||||
v = append(v, pbv)
|
||||
}
|
||||
valField.Set(reflect.ValueOf(v))
|
||||
|
||||
case reflect.Int64:
|
||||
var v []int64
|
||||
for _, bv := range ba {
|
||||
pbv, err := strconv.ParseInt(string(bv), 10, 64)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Unable to parse int for attribute %q", attributeName)
|
||||
}
|
||||
v = append(v, pbv)
|
||||
}
|
||||
valField.Set(reflect.ValueOf(v))
|
||||
|
||||
case reflect.String:
|
||||
var v []string
|
||||
for _, bv := range ba {
|
||||
v = append(v, strings.Trim(string(bv), `"`))
|
||||
}
|
||||
valField.Set(reflect.ValueOf(v))
|
||||
|
||||
default:
|
||||
return errors.Errorf("Unsupported type: []%s", typeField.Type.Elem().Kind())
|
||||
}
|
||||
|
||||
default:
|
||||
return errors.Errorf("Unsupported type: %s", typeField.Type.Kind())
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getSingleValue(in []byte, name string) []byte {
|
||||
rex := regexp.MustCompile(fmt.Sprintf(singleLineValue, name))
|
||||
|
||||
var scanner = bufio.NewScanner(bytes.NewReader(in))
|
||||
for scanner.Scan() {
|
||||
if rex.Match(scanner.Bytes()) {
|
||||
grp := rex.FindSubmatch(scanner.Bytes())
|
||||
return grp[1]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getArrayValues(in []byte, name string) ([][]byte, error) {
|
||||
rex := regexp.MustCompile(fmt.Sprintf(arrayLineValue, name))
|
||||
var out [][]byte
|
||||
|
||||
var scanner = bufio.NewScanner(bytes.NewReader(in))
|
||||
for scanner.Scan() {
|
||||
if rex.Match(scanner.Bytes()) {
|
||||
grp := rex.FindSubmatch(scanner.Bytes())
|
||||
|
||||
if len(grp[1]) == 0 {
|
||||
arrayLen, err := strconv.Atoi(string(grp[3]))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Unable to parse array capacity")
|
||||
}
|
||||
out = make([][]byte, arrayLen)
|
||||
continue
|
||||
}
|
||||
|
||||
if len(grp[2]) == 0 {
|
||||
out = append(out, grp[3])
|
||||
continue
|
||||
}
|
||||
|
||||
idx, err := strconv.Atoi(string(grp[2]))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Unable to parse array index")
|
||||
}
|
||||
|
||||
out[idx] = make([]byte, len(grp[3]))
|
||||
for i, b := range grp[3] {
|
||||
out[idx][i] = b
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return out, errors.Wrap(scanner.Err(), "Unable to parse array lines")
|
||||
}
|
||||
|
||||
func isNilValue(in []byte) bool {
|
||||
return reflect.DeepEqual(in, []byte("nil"))
|
||||
}
|
|
@ -4,6 +4,8 @@ import (
|
|||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
@ -15,6 +17,10 @@ func float2sii(f float32) ([]byte, error) {
|
|||
err error
|
||||
)
|
||||
|
||||
if math.Floor(float64(f)) == float64(f) {
|
||||
return []byte(fmt.Sprintf("%.0f", f)), nil
|
||||
}
|
||||
|
||||
err = binary.Write(buf, binary.BigEndian, f)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Unable to encode float")
|
||||
|
|
|
@ -49,7 +49,7 @@ func parseSIIPlainFile(r io.Reader) (*Unit, error) {
|
|||
|
||||
case line == "}":
|
||||
if inBlock {
|
||||
if err := processBlock(unit, blockClass, blockName, blockContent); err != nil {
|
||||
if err := processBlock(unit, blockClass, blockName, bytes.Trim(blockContent, "\n")); err != nil {
|
||||
return nil, errors.Wrap(err, "Unable to process block")
|
||||
}
|
||||
|
||||
|
|
19
sii.go
19
sii.go
|
@ -117,8 +117,23 @@ func WriteUnitFile(filename string, encrypt bool, data *Unit) error {
|
|||
return ErrNoEncryptionKeySet
|
||||
}
|
||||
|
||||
// FIXME: Implement this
|
||||
return errors.New("Not implemented")
|
||||
var buf = new(bytes.Buffer)
|
||||
|
||||
if err := writeSIIPlainFile(data, buf); err != nil {
|
||||
return errors.Wrap(err, "Unable to create SII file content")
|
||||
}
|
||||
|
||||
// FIXME: Implement encryption
|
||||
|
||||
// Create output file
|
||||
f, err := os.Create(filename)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Unable to open output file")
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
_, err = buf.WriteTo(f)
|
||||
return errors.Wrap(err, "Unable to write buffer")
|
||||
}
|
||||
|
||||
func readFTHeader(f io.ReaderAt) ([]byte, error) {
|
||||
|
|
6
unit.go
6
unit.go
|
@ -25,9 +25,9 @@ func (r *RawBlock) Init(class, name string) {
|
|||
r.blockClass = class
|
||||
r.blockName = name
|
||||
}
|
||||
func (r RawBlock) MarshalSII() []byte { return r.Data }
|
||||
func (r RawBlock) Name() string { return r.blockName }
|
||||
func (r RawBlock) Class() string { return r.blockClass }
|
||||
func (r RawBlock) MarshalSII() ([]byte, error) { return r.Data, nil }
|
||||
func (r RawBlock) Name() string { return r.blockName }
|
||||
func (r RawBlock) Class() string { return r.blockClass }
|
||||
func (r *RawBlock) UnmarshalSII(in []byte) error {
|
||||
r.Data = in
|
||||
return nil
|
||||
|
|
Loading…
Reference in a new issue