From edf52767ecc7dd27f6197ababe56bbf62e228f52 Mon Sep 17 00:00:00 2001 From: Tormod Erevik Lea Date: Sun, 2 Apr 2017 21:00:00 +0200 Subject: [PATCH] unknown: refactor handling of unknown fields and messages Must now be enabled using DecodeOptions. Updates #6. --- fit.go | 19 ++++++------------- reader.go | 46 ++++++++++++++++++++++++++++++++++++++++------ unkown.go | 45 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+), 19 deletions(-) create mode 100644 unkown.go diff --git a/fit.go b/fit.go index 0afacd0..df2cd1e 100644 --- a/fit.go +++ b/fit.go @@ -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 @@ -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) } diff --git a/reader.go b/reader.go index 97e3292..63c3afa 100644 --- a/reader.go +++ b/reader.go @@ -11,6 +11,7 @@ import ( "math" "os" "reflect" + "sort" "strconv" "time" @@ -47,6 +48,9 @@ type decoder struct { opts decodeOptions + unknownFields map[unknownField]int + unknownMessages map[MesgNum]int + h Header fit *Fit } @@ -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 { @@ -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) @@ -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 { @@ -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]) @@ -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)) +} diff --git a/unkown.go b/unkown.go new file mode 100644 index 0000000..9e6f33a --- /dev/null +++ b/unkown.go @@ -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 +}