Skip to content

Commit

Permalink
unknown: refactor handling of unknown fields and messages
Browse files Browse the repository at this point in the history
Must now be enabled using DecodeOptions.

Updates #6.
  • Loading branch information
tormoder committed Apr 2, 2017
1 parent a9e486f commit edf5276
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 19 deletions.
19 changes: 6 additions & 13 deletions fit.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ type Fit struct {
TimestampCorrelation *TimestampCorrelationMsg
DeviceInfo *DeviceInfoMsg

// UnknownMessages is a map that maps an unknown message number to how
// many times the message was encountered during encoding.
UnknownMessages map[MesgNum]int
// UnknownMessages is a slice of unknown messages encountered during
// decoding. It is sorted by message number.
UnknownMessages []UnknownMessage

// UnknownFields is a map that maps an unknown field to how many times
// the field was encountered during encoding.
UnknownFields map[UnknownField]int
// UnknownFields is a slice of unknown fields for known messages
// encountered during decoding. It is sorted by message number.
UnknownFields []UnknownField

msgAdder msgAdder

Expand All @@ -50,13 +50,6 @@ type Fit struct {
segmentList *SegmentListFile
}

// UnknownField represents an unknown FIT message field not found in the
// official profile. It contains the global message and field number.
type UnknownField struct {
MesgNum MesgNum
FieldNum byte
}

type msgAdder interface {
add(reflect.Value)
}
Expand Down
46 changes: 40 additions & 6 deletions reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"math"
"os"
"reflect"
"sort"
"strconv"
"time"

Expand Down Expand Up @@ -47,6 +48,9 @@ type decoder struct {

opts decodeOptions

unknownFields map[unknownField]int
unknownMessages map[MesgNum]int

h Header
fit *Fit
}
Expand Down Expand Up @@ -126,8 +130,8 @@ func (d *decoder) decode(r io.Reader, headerOnly, fileIDOnly, crcOnly bool) erro
goto crc
}

d.fit.UnknownMessages = make(map[MesgNum]int)
d.fit.UnknownFields = make(map[UnknownField]int)
d.unknownMessages = make(map[MesgNum]int)
d.unknownFields = make(map[unknownField]int)

err = d.parseFileIdMsg()
if err != nil {
Expand Down Expand Up @@ -183,6 +187,13 @@ func (d *decoder) decode(r io.Reader, headerOnly, fileIDOnly, crcOnly bool) erro
}
}

if d.opts.unknownFields {
d.handleUnknownFields()
}
if d.opts.unknownMessages {
d.handleUnknownMessages()
}

crc:
if err = binary.Read(d.r, binary.LittleEndian, &d.fit.CRC); err != nil {
err = noEOF(err)
Expand Down Expand Up @@ -535,8 +546,8 @@ func (d *decoder) parseDataMessage(recordHeader byte, compressed bool) (reflect.
knownMsg := knownMsgNums[dm.globalMsgNum]
if knownMsg {
msgv = getMesgAllInvalid(dm.globalMsgNum)
} else {
d.fit.UnknownMessages[dm.globalMsgNum]++
} else if d.opts.unknownMessages {
d.unknownMessages[dm.globalMsgNum]++
}

if !compressed {
Expand Down Expand Up @@ -588,8 +599,8 @@ func (d *decoder) parseDataFields(dm *defmsg, knownMsg bool, msgv reflect.Value)
if pfield.btype != base.String && pfield.array == 0 {
padding = pfield.btype.Size() - dsize
}
} else {
d.fit.UnknownFields[UnknownField{dm.globalMsgNum, dfield.num}]++
} else if d.opts.unknownFields {
d.unknownFields[unknownField{dm.globalMsgNum, dfield.num}]++
}

err := d.readFull(d.tmp[0:dsize])
Expand Down Expand Up @@ -845,3 +856,26 @@ func noEOF(err error) error {
}
return err
}

func (d *decoder) handleUnknownFields() {
d.fit.UnknownFields = make([]UnknownField, 0, len(d.unknownFields))
for field, count := range d.unknownFields {
d.fit.UnknownFields = append(d.fit.UnknownFields, UnknownField{
MesgNum: field.mesgNum,
FieldNum: field.fieldNum,
Count: count,
})
}
sort.Sort(unknownFieldSlice(d.fit.UnknownFields))
}

func (d *decoder) handleUnknownMessages() {
d.fit.UnknownMessages = make([]UnknownMessage, 0, len(d.unknownMessages))
for mesgNum, count := range d.unknownMessages {
d.fit.UnknownMessages = append(d.fit.UnknownMessages, UnknownMessage{
MesgNum: mesgNum,
Count: count,
})
}
sort.Sort(unknownMessageSlice(d.fit.UnknownMessages))
}
45 changes: 45 additions & 0 deletions unkown.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package fit

type unknownField struct {
mesgNum MesgNum
fieldNum byte
}

// UnknownField represents an unknown FIT message field for a known message
// found in the official profile. It contains the message and field number, in
// addition to how many times the field for a specific message was encountered
// during decoding.
type UnknownField struct {
MesgNum MesgNum
FieldNum byte
Count int
}

type unknownFieldSlice []UnknownField

func (p unknownFieldSlice) Len() int { return len(p) }
func (p unknownFieldSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func (p unknownFieldSlice) Less(i, j int) bool {
if p[i].MesgNum < p[j].MesgNum {
return true
} else if p[i].MesgNum < p[j].MesgNum {
return false
}
return p[i].FieldNum < p[j].FieldNum
}

// UnknownMessage represents an unknown FIT message not found in the official
// profile. It contains the message number and how many times the was
// encountered during decoding.
type UnknownMessage struct {
MesgNum MesgNum
Count int
}

type unknownMessageSlice []UnknownMessage

func (p unknownMessageSlice) Len() int { return len(p) }
func (p unknownMessageSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func (p unknownMessageSlice) Less(i, j int) bool {
return p[i].MesgNum < p[j].MesgNum
}

0 comments on commit edf5276

Please sign in to comment.