Example #1
0
// CheckIntegrity verifies the FIT header CRC.
func (h Header) CheckIntegrity() error {
	if err := checkProtocolVersion(h.ProtocolVersion); err != nil {
		return err
	}
	if string(h.DataType[:len(h.DataType)]) != fitDataTypeString {
		return errNotFit
	}
	if h.Size == headerSizeNoCRC {
		return nil
	}
	if h.CRC == 0 {
		return nil
	}

	crc := dyncrc16.New()
	bh := make([]byte, h.Size)
	bh[0] = h.Size
	bh[1] = h.ProtocolVersion
	le.PutUint16(bh[2:4], h.ProfileVersion)
	le.PutUint32(bh[4:8], h.DataSize)
	copy(bh[8:12], h.DataType[:])
	le.PutUint16(bh[12:14], h.CRC)

	if crc.Sum16() != 0x0000 {
		return errHdrCRC
	}

	return nil
}
Example #2
0
func (d *decoder) decodeHeader() error {
	size, err := d.r.ReadByte()
	if err != nil {
		return err
	}
	if size != headerSizeCRC && size != headerSizeNoCRC {
		return errHeaderSize
	}
	d.h.Size = size

	if err := d.readFull(d.tmp[:size-1]); err != nil {
		return err
	}

	if err = checkProtocolVersion(d.tmp[0]); err != nil {
		return err
	}
	d.h.ProtocolVersion = d.tmp[0]
	d.h.ProfileVersion = le.Uint16(d.tmp[1:3])
	d.h.DataSize = le.Uint32(d.tmp[3:7])

	if string(d.tmp[7:11]) != fitDataTypeString {
		return errNotFit
	}
	copy(d.h.DataType[:], d.tmp[7:11])

	if size == headerSizeNoCRC {
		return nil
	}

	d.h.CRC = le.Uint16(d.tmp[11:13])
	if d.h.CRC == 0x0000 {
		return nil
	}

	checksum := dyncrc16.New()
	checksum.Write([]byte{size})
	checksum.Write(d.tmp[:size-1])

	if checksum.Sum16() != 0x0000 {
		return errHdrCRC
	}

	return nil
}
Example #3
0
func (d *decoder) decode(r io.Reader, headerOnly, fileIDOnly, crcOnly bool) error {
	d.crc = dyncrc16.New()
	tr := io.TeeReader(r, d.crc)

	// Add buffering if r does not provide ReadByte.
	if rr, ok := tr.(reader); ok {
		d.r = rr
	} else {
		d.r = bufio.NewReader(tr)
	}

	err := d.decodeHeader()
	if err != nil {
		return fmt.Errorf("error decoding header: %v", err)
	}

	d.fit = new(Fit)
	d.fit.Header = d.h

	if debug {
		log.Println("header decoded:", d.h)
	}

	if headerOnly {
		return nil
	}

	if crcOnly {
		_, err = io.CopyN(ioutil.Discard, d.r, int64(d.h.DataSize))
		if err != nil {
			return fmt.Errorf("error parsing data: %v", err)
		}
		goto crc
	}

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

	err = d.parseFileIdMsg()
	if err != nil {
		return fmt.Errorf("error parsing file id message: %v", err)
	}
	if fileIDOnly {
		return nil
	}

	err = d.initFileType()
	if err != nil {
		return err
	}

	for d.n < d.h.DataSize-2 {
		var (
			b   byte
			dm  *defmsg
			msg reflect.Value
		)

		b, err = d.readByte()
		if err != nil {
			return fmt.Errorf("error parsing record header: %v", err)
		}

		switch {

		case (b & compressedHeaderMask) == compressedHeaderMask:
			msg, err = d.parseDataMessage(b, true)
			if err != nil {
				return fmt.Errorf("compressed timestamp message: %v", err)
			}
			if msg.IsValid() {
				d.fit.add(msg)
			}
		case (b & headerTypeMask) == mesgDefinitionMask:
			dm, err = d.parseDefinitionMessage(b)
			if err != nil {
				return fmt.Errorf("parsing definition message: %v", err)
			}
			d.defmsgs[dm.localMsgType] = dm
		case (b & mesgHeaderMask) == mesgHeaderMask:
			msg, err = d.parseDataMessage(b, false)
			if err != nil {
				return fmt.Errorf("parsing data message: %v", err)
			}
			if msg.IsValid() {
				d.fit.add(msg)
			}
		default:
			return fmt.Errorf("unknown record header, got: %#x", b)
		}
	}

crc:
	if err = binary.Read(d.r, binary.LittleEndian, &d.fit.CRC); err != nil {
		if err == io.EOF {
			err = io.ErrUnexpectedEOF
		}
		return fmt.Errorf("error parsing file CRC: %v", err)
	}

	if d.crc.Sum16() != 0x0000 {
		return IntegrityError("file checksum failed")
	}

	return nil
}