Skip to content

Commit

Permalink
finish up the struct tag parsing for max length on fields
Browse files Browse the repository at this point in the history
  • Loading branch information
whyrusleeping committed May 14, 2022
1 parent 4f561c4 commit 0820343
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 18 deletions.
62 changes: 49 additions & 13 deletions gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,12 @@ func doTemplate(w io.Writer, info interface{}, templ string) error {
"ReadHeader": func(rdr string) string {
return fmt.Sprintf(`%s.ReadHeader()`, rdr)
},
//todo do it here
"MaxLen": func(val int, def string) string {
if val <= 0 {
return def
}
return fmt.Sprintf("%d", val)
},
}).Parse(templ))

return t.Execute(w, info)
Expand Down Expand Up @@ -181,14 +186,21 @@ func ParseTypeInfo(i interface{}) (*GenTypeInfo, error) {
mapk := f.Name
usrMaxLen := NoUsrMaxLen
tagval := f.Tag.Get("cborgen")
if len(tagval) > len(MaxLenTag) && tagval[0:len(MaxLenTag)] == MaxLenTag {
var err error
usrMaxLen, err = strconv.Atoi(tagval[len(MaxLenTag):])
tags, err := tagparse(tagval)
if err != nil {
return nil, fmt.Errorf("invalid tag format: %w", err)
}

if tags["name"] != "" {
mapk = tags["name"]
}
if msize := tags["maxlen"]; msize != "" {
val, err := strconv.Atoi(msize)
if err != nil {
return nil, fmt.Errorf("failed to parse specified length in max len tag %w", err)
return nil, fmt.Errorf("maxsize tag value was not valid: %w", err)
}
} else if tagval != "" {
mapk = tagval

usrMaxLen = val
}

out.Fields = append(out.Fields, Field{
Expand All @@ -204,6 +216,30 @@ func ParseTypeInfo(i interface{}) (*GenTypeInfo, error) {
return &out, nil
}

func tagparse(v string) (map[string]string, error) {
out := make(map[string]string)
for _, elem := range strings.Split(v, ",") {
elem = strings.TrimSpace(elem)
if elem == "" {
continue
}

if strings.Contains(elem, "=") {
parts := strings.Split(elem, "=")
if len(parts) != 2 {
return nil, fmt.Errorf("struct tags with params must be of form X=Y")
}

out[strings.TrimSpace(parts[0])] = strings.TrimSpace(parts[1])
} else {
out["name"] = elem
}

}

return out, nil
}

func (gti GenTypeInfo) TupleHeader() []byte {
return CborEncodeMajorType(MajArray, uint64(len(gti.Fields)))
}
Expand Down Expand Up @@ -238,7 +274,7 @@ func emitCborMarshalStringField(w io.Writer, f Field) error {
}

return doTemplate(w, f, `
if len({{ .Name }}) > {{ .MaxLen }} {
if len({{ .Name }}) > {{ MaxLen .MaxLen "cbg.MaxLength" }} {
return xerrors.Errorf("Value in field {{ .Name | js }} was too long")
}
Expand Down Expand Up @@ -412,7 +448,7 @@ func emitCborMarshalSliceField(w io.Writer, f Field) error {
// Note: this re-slices the slice to deal with arrays.
if e.Kind() == reflect.Uint8 {
return doTemplate(w, f, `
if len({{ .Name }}) > {{ .MaxLen }} {
if len({{ .Name }}) > {{ MaxLen .MaxLen "cbg.ByteArrayMaxLen" }} {
return xerrors.Errorf("Byte array in field {{ .Name }} was too long")
}
Expand All @@ -429,7 +465,7 @@ func emitCborMarshalSliceField(w io.Writer, f Field) error {
}

err := doTemplate(w, f, `
if len({{ .Name }}) > {{ .MaxLen }} {
if len({{ .Name }}) > {{ MaxLen .MaxLen "cbg.MaxLength" }} {
return xerrors.Errorf("Slice value in field {{ .Name }} was too long")
}
Expand Down Expand Up @@ -884,7 +920,7 @@ func emitCborUnmarshalSliceField(w io.Writer, f Field) error {

if e.Kind() == reflect.Uint8 {
return doTemplate(w, f, `
if extra > {{ .MaxLen }} {
if extra > {{ MaxLen .MaxLen "cbg.ByteArrayMaxLen" }} {
return fmt.Errorf("{{ .Name }}: byte array too large (%d)", extra)
}
if maj != cbg.MajByteString {
Expand All @@ -908,7 +944,7 @@ func emitCborUnmarshalSliceField(w io.Writer, f Field) error {
}

if err := doTemplate(w, f, `
if extra > {{ .MaxLen }} {
if extra > {{ MaxLen .MaxLen "cbg.MaxLength" }} {
return fmt.Errorf("{{ .Name }}: array too large (%d)", extra)
}
`); err != nil {
Expand Down Expand Up @@ -1208,7 +1244,7 @@ func (t *{{ .Name}}) UnmarshalCBOR(r io.Reader) (err error) {
return fmt.Errorf("cbor input should be of type map")
}
if extra > {{ .MaxLen }} {
if extra > cbg.MaxLength {
return fmt.Errorf("{{ .Name }}: map struct too large (%d)", extra)
}
Expand Down
76 changes: 76 additions & 0 deletions testing/cbor_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 5 additions & 5 deletions testing/roundtrip_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -361,17 +361,17 @@ func TestLargeField(t *testing.T) {
}
enc := buf.Bytes()
typ.LargeBytes = make([]byte, 0) // reset
if err := typ.LargeBytes.UnmarshalCBOR(bytes.NewReader(enc)); err != nil {
if err := typ.UnmarshalCBOR(bytes.NewReader(enc)); err != nil {
t.Error(err)
}

// 16 MiB > 10, fails
bs := make([]byte, 2<<23)
badType = BigField{
bs = make([]byte, 2<<23)
badType := BigField{
LargeBytes: bs,
}
buf := new(bytes.Buffer)
err := badTyp.MarshalCBOR(buf)
buf = new(bytes.Buffer)
err := badType.MarshalCBOR(buf)
if err == nil {
t.Fatal("buffer bigger than specified in struct tag should fail")
}
Expand Down

0 comments on commit 0820343

Please sign in to comment.