QtFit  0.1
Internal library development documentation
All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
FitStreamReaderPrivate Class Reference

Provides private implementation for FitStreamReader. More...

Collaboration diagram for FitStreamReaderPrivate:
[legend]

Public Types

typedef qsizetype size_t
 Size type for size-related operations.
 

Public Member Functions

 FitStreamReaderPrivate (FitStreamReader *const q)
 Constructs a FitStreamReaderPrivate object, with public implementation q. More...
 
virtual ~FitStreamReaderPrivate ()
 Destroys the FitStreamReaderPrivate object.
 

Public Attributes

QByteArray data
 FIT File data (alternative to device).
 
size_t dataOffset
 Current position within data.
 
QIODevice * device
 FIT File IO stream (alternative to data and dataOffset).
 

Protected Member Functions

template<class T >
size_t bytesAvailable () const
 Returns the number of bytes currently available for reading. More...
 
template<class T >
bool parseFileHeader ()
 Reads and parses the FIT stream's file header. More...
 
template<class T >
bool parseDefinitionMessage ()
 Reads and parses a FIT Definition Message. More...
 
template<class T >
AbstractDataMessageparseDataMessage ()
 Reads and parses a FIT Data Message. More...
 
template<class T >
quint8 peekByte (const int pos=0) const
 Peeks the next pos'th byte in the FIT stream. More...
 
template<class T >
QByteArray readBytes (const size_t size)
 Reads the next size bytes from the FIT stream. More...
 
template<class T >
QByteArray readFileHeader ()
 Reads all bytes of the FIT stream file header. More...
 
template<class T >
AbstractDataMessagereadNextDataMessage ()
 Reads up to, and including, the next FIT Data Message. More...
 
template<>
FitStreamReaderPrivate::size_t bytesAvailable () const
 Specialisation for reading from QByteArray objects. More...
 
template<>
FitStreamReaderPrivate::size_t bytesAvailable () const
 Specialisation for reading from QIODevice streams. More...
 
template<>
quint8 peekByte (const int pos) const
 Specialisation for reading from QByteArray objects. More...
 
template<>
quint8 peekByte (const int pos) const
 Specialisation for reading from QIODevice streams. More...
 
template<>
QByteArray readBytes (const size_t size)
 Specialisation for reading from QIODevice streams. More...
 
template<>
QByteArray readBytes (const size_t size)
 Specialisation for reading from QIODevice streams. More...
 

Static Protected Member Functions

static quint16 fitChecksum (const QByteArray &data)
 Calculates a checksum, as per the algorithm used by FIT file headers. More...
 
static bool isDefinitionMessage (const quint8 recordHeader)
 Returns true if recordHeader indicates a Definition Message, otherwise false. More...
 

Protected Attributes

FitStreamReader *const q_ptr
 Internal q-pointer.
 

Private Attributes

QVersionNumber protocolVersion
 Protocol version read from the parsed FIT file header.
 
QVersionNumber profileVersion
 Protocol version read from the parsed FIT file header.
 
quint32 expectedDataSize
 Total size, in bytes, expected to comprise the FIT file.
 
QHash< int, DataDefinitiondataDefinitions
 Local message types to current data definitions.
 
QHash< int, int > recordSizes
 Local message types to current record sizes.
 

Detailed Description

Provides private implementation for FitStreamReader.

Definition at line 40 of file fitstreamreader_p.h.

Constructor & Destructor Documentation

◆ FitStreamReaderPrivate()

FitStreamReaderPrivate::FitStreamReaderPrivate ( FitStreamReader *const  q)
explicit

Constructs a FitStreamReaderPrivate object, with public implementation q.

Parameters
qPointer to public implementation.

Definition at line 267 of file fitstreamreader.cpp.

268  : dataOffset(0), device(nullptr), q_ptr(q)
269 {
270 
271 }
QIODevice * device
FIT File IO stream (alternative to data and dataOffset).
FitStreamReader *const q_ptr
Internal q-pointer.
size_t dataOffset
Current position within data.

Member Function Documentation

◆ bytesAvailable() [1/3]

template<>
FitStreamReaderPrivate::size_t FitStreamReaderPrivate::bytesAvailable ( ) const
protected

Specialisation for reading from QByteArray objects.

Returns
the number of bytes available for reading.

Definition at line 294 of file fitstreamreader.cpp.

295 {
296  Q_ASSERT(device == nullptr);
297  return data.size() - dataOffset;
298 }
QByteArray data
FIT File data (alternative to device).

References data, dataOffset, and device.

◆ bytesAvailable() [2/3]

template<>
FitStreamReaderPrivate::size_t FitStreamReaderPrivate::bytesAvailable ( ) const
protected

Specialisation for reading from QIODevice streams.

Returns
the number of bytes available for reading.

Definition at line 305 of file fitstreamreader.cpp.

306 {
307  Q_ASSERT(device != nullptr);
308  return device->bytesAvailable();
309 }

References device.

◆ bytesAvailable() [3/3]

template<class T >
FitStreamReaderPrivate::bytesAvailable ( ) const
protected

Returns the number of bytes currently available for reading.

Returns
the number of bytes available for reading.

◆ fitChecksum()

quint16 FitStreamReaderPrivate::fitChecksum ( const QByteArray &  data)
inlinestaticprotected

Calculates a checksum, as per the algorithm used by FIT file headers.

Todo:
Move this somewhere appropriate; its not specific to FitStreamReader, but rather would be useful eventually for a FitStreamWriter class too. I guess its safe to keep in a private class for now, so it can then be moved without affecting the library's binary interface.
Parameters
dataFIT file header to calculate the checksum for.
Returns
16-bit checksum for data.

Definition at line 678 of file fitstreamreader.cpp.

679 {
680  quint16 checksum=0;
681  for (const auto &byte: data) {
682  static const quint16 crcTable[16] = {
683  0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401,
684  0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400
685  };
686  for (int byteShift=0; byteShift<=4; byteShift+=4) {
687  const quint16 tmp = crcTable[checksum & 0xF];
688  checksum = (checksum >> 4) & 0x0FFF;
689  checksum = checksum ^ tmp ^ crcTable[(byte >> byteShift) & 0xF];
690  }
691  }
692  return checksum;
693 }

References data.

Referenced by parseFileHeader().

Here is the caller graph for this function:

◆ isDefinitionMessage()

bool FitStreamReaderPrivate::isDefinitionMessage ( const quint8  recordHeader)
inlinestaticprotected

Returns true if recordHeader indicates a Definition Message, otherwise false.

Parameters
recordHeaderA FIT Data Record header byte.
Returns
true if recordHeader indicates a Definition Message, otherwise false.

Definition at line 702 of file fitstreamreader.cpp.

703 {
704  // For definition messages, bit 7 must be off (bit 7 on would indicate a Compressed Timestamp
705  // Data Message, which cannot be a Definition Message), and bit 6 must be on (otherwise this
706  // woud be a Normal Data Message, not a Definition Message).
707  return ((recordHeader >> 6) == 1); // Match bit 7 on and 6 off; ie 01xxxxxx.
708 }

Referenced by parseDataMessage(), parseDefinitionMessage(), and readNextDataMessage().

Here is the caller graph for this function:

◆ parseDataMessage()

template<class T >
AbstractDataMessage * FitStreamReaderPrivate::parseDataMessage
protected

Reads and parses a FIT Data Message.

Note, this function assumes that the next item in the FIT stream is indeed a Data Message (the caller should have already determined this). Though it is perfectly acceptable that the message may not be completely available yet (in which case false will be returned).

This fuction will, as part of decoding the message, look-up the Data Message's definition, which must have been stored previously by one or more Definition Messages being processed earlier. If no matching definition is found, false will be returned.

Returns
true if the Data Message was successfully read and parsed, false otherwise.
Todo:
Process timeOffset.
Todo:
Set error code.

Definition at line 493 of file fitstreamreader.cpp.

494 {
495  Q_ASSERT(bytesAvailable<T>());
496  qDebug() << "parsing data message";
497  const quint8 recordHeader = peekByte<T>();
498  qDebug() << __func__ << "recordHeader" << recordHeader;
499  Q_ASSERT_X(!isDefinitionMessage(recordHeader), "parseDataMessage",
500  "FIT record header does not indiciate a data message");
501 
502  // Parse the record header.
503  quint8 localMessageType;
504  if (recordHeader & (1 << 7)) { // Compressed Timestamp Header.
505  qDebug() << __func__ << "Compressed Timestamp Header";
506  localMessageType = ((recordHeader >> 4) & 0x7);
507  const quint8 timeOffset = (recordHeader & 0xF);
508  qDebug() << "time offset" << timeOffset;
509  /// \todo Process timeOffset.
510  } else { // Normal (Data Message) Header
511  qDebug() << __func__ << "Normal (Data Message) Header";
512  qDebug() << __func__ << "reserved5" << (recordHeader & (1 << 5));
513  qDebug() << __func__ << "reserved4" << (recordHeader & (1 << 4));
514  localMessageType = (recordHeader & 0xF); // Least significant 4 bits.
515  }
516  qDebug() << __func__ << "local message type" << localMessageType;
517 
518  // Lookup the record's field definitions.
519  if (!dataDefinitions.contains(localMessageType)) {
520  qWarning() << "No definition for local message type" << localMessageType;
521  /// \todo Set error code.
522  return nullptr; // FIT data is corrupt; we cannot safely continue parsing.
523  }
524  const DataDefinition defn = dataDefinitions.value(localMessageType);
525 
526  // Parse record's Data Fields.
527  qDebug() << __func__ << "record size" << defn.recordSize;
528  if (defn.recordSize == 0) {
529  qWarning() << "record size is zero"; // Not really sure what to do here.
530  return nullptr;
531  }
532  const QByteArray record = readBytes<T>(defn.recordSize+1);
533  if (record.isEmpty()) {
534  return nullptr; // Not enough bytes.
535  }
536  qDebug() << "record" << record.mid(1);
537  return AbstractDataMessage::fromData(&defn, record.mid(1));
538 }
static AbstractDataMessage * fromData(const DataDefinition *const defn, const QByteArray &record)
Constructs the relevant AbstractDataMessage-derived class to parse record according to defn.
static bool isDefinitionMessage(const quint8 recordHeader)
Returns true if recordHeader indicates a Definition Message, otherwise false.
QHash< int, DataDefinition > dataDefinitions
Local message types to current data definitions.
Data Message definition.
Definition: types_p.h:83
int recordSize
Total size, in byetes, of all fields in the described Data Message.
Definition: types_p.h:101

References dataDefinitions, AbstractDataMessage::fromData(), isDefinitionMessage(), and DataDefinition::recordSize.

Here is the call graph for this function:

◆ parseDefinitionMessage()

template<class T >
bool FitStreamReaderPrivate::parseDefinitionMessage
protected

Reads and parses a FIT Definition Message.

Note, this function assumes that the next item in the FIT stream is indeed a Definition Message (the caller should have already determined this). Though it is perfectly acceptable that the message may not be completely available yet (in which case false will be returned).

Returns
true if the Definition Message was successfully read and parsed, false otherwise.

Definition at line 388 of file fitstreamreader.cpp.

389 {
390  // Parse the record header.
391  qDebug() << "parsing definition message";
392  Q_ASSERT(bytesAvailable<T>());
393  const quint8 recordHeader = peekByte<T>();
394  qDebug() << __func__ << "recordHeader" << recordHeader;
395  Q_ASSERT_X(isDefinitionMessage(recordHeader), "parseDefinitionMessage",
396  "FIT record header does not indiciate a definition message");
397  const bool hasDevFields = (recordHeader & (1 << 5));
398  qDebug() << __func__ << "has dev fields" << hasDevFields;
399  qDebug() << __func__ << "reserved" << (recordHeader & (1 << 4));
400  const quint8 localMessageType = (recordHeader & 0xF); // Least significant 4 bits.
401  qDebug() << __func__ << "local message type" << localMessageType;
402 
403  // Read the completed definition record (if available).
404  if (bytesAvailable<T>() < 6) {
405  return false; // Not enough bytes.
406  }
407  const quint8 numberOfFields = peekByte<T>(5);
408  qDebug() << __func__ << "number of fields" << numberOfFields;
409  int numberOfDevFields = 0;
410  if (hasDevFields) {
411  const int offsetToNumberOfDevFields = 6 + (numberOfFields * 3);
412  qDebug() << __func__ << "offset to number of dev fields" << offsetToNumberOfDevFields;
413  if (bytesAvailable<T>() < offsetToNumberOfDevFields) {
414  return false; // Not enough bytes.
415  }
416  numberOfDevFields = peekByte<T>(offsetToNumberOfDevFields);
417  }
418  const int recordSize = 6 + (numberOfFields * 3) + (hasDevFields ? 1 + (numberOfDevFields * 3) : 0);
419  qDebug() << __func__ << "number of dev fields" << numberOfDevFields;
420  qDebug() << __func__ << "record size" << recordSize;
421  const QByteArray record = readBytes<T>(recordSize);
422  if (record.isEmpty()) {
423  return false; // Not enough bytes.
424  }
425 
426  // Parse the rest of the definition record.
427  DataDefinition defn;
428  defn.recordSize = 0;
429  defn.architecture = static_cast<Architecture>(record.at(2));
430  qDebug() << __func__ << "architecture" << (int)defn.architecture;
431  qDebug() << record.mid(3,2);
433  ? qFromBigEndian<quint16>(record.mid(3,2))
434  : qFromLittleEndian<quint16>(record.mid(3,2)));
435  qDebug() << __func__ << "header" << (quint8)record.at(0);
436  qDebug() << __func__ << "reserved" << (quint8)record.at(1);
437  qDebug() << __func__ << "msgNum" << (int)defn.globalMessageNumber;
438 
439  // Parse the definition fields.
440  for (int i=0; i < numberOfFields; ++i) {
441  const int pos = 6 + (i * 3);
442  FieldDefinition field;
443  field.number = record.at(pos);
444  field.size = record.at(pos+1);
445  field.baseType = static_cast<FitBaseType>(record.at(pos+2));
446  qDebug() << __func__ << "field" << i << "number" << field.number;
447  qDebug() << __func__ << "field" << i << "size" << field.size;
448  qDebug() << __func__ << "field" << i << "type" << static_cast<quint8>(field.baseType);
449  defn.fieldDefinitions.append(field);
450  defn.recordSize += field.size;
451  }
452  Q_ASSERT(defn.fieldDefinitions.size() == numberOfFields);
453  qDebug() << __func__ << "defn record size" << defn.recordSize;
454 
455  // Parse the definition fields.
456  Q_ASSERT(hasDevFields || (numberOfDevFields == 0));
457  for (int i=0; i < numberOfDevFields; ++i) {
458  const int pos = 6 + (numberOfFields * 3) + 1 + (i * 3);
460  field.fieldNumber = record.at(pos);
461  field.size = record.at(pos+1);
462  field.devDataIndex = record.at(pos+2);
463  qDebug() << __func__ << "dev field" << i << "number" << field.fieldNumber;
464  qDebug() << __func__ << "dev field" << i << "size" << field.size;
465  qDebug() << __func__ << "dev field" << i << "dataIndex" << field.devDataIndex;
466  defn.developerFieldDefinitions.append(field);
467  defn.recordSize += field.size;
468  }
469  Q_ASSERT(defn.developerFieldDefinitions.size() == numberOfDevFields);
470  qDebug() << __func__ << "defn record size" << defn.recordSize;
471  if (defn.recordSize == 0) {
472  qWarning() << "defintion record size is zero";
473  }
474 
475  // Record the definition data for future Data Messages.
476  dataDefinitions.insert(localMessageType, defn);
477  return true;
478 }
QList< FieldDefinition > fieldDefinitions
Definitons list of all fields, if any, present in the described Data Message.
Definition: types_p.h:88
QList< DeveloperFieldDefinition > developerFieldDefinitions
Definitions list of all custom fields, if any, present in the described Data Message.
Definition: types_p.h:91
Architecture architecture
Architecture type for any multi-byte fields.
Definition: types_p.h:84
MesgNum globalMessageNumber
FIT Global Message Number the Data Message represents.
Definition: types_p.h:85
Custom developer field definition.
Definition: types_p.h:55
quint8 fieldNumber
Maps to the field_definition_number of a field_description Message.
Definition: types_p.h:56
quint8 size
Size (in bytes) of the specified FIT message’s field.
Definition: types_p.h:57
quint8 devDataIndex
Maps to the developer_data_index of a developer_data_id Message.
Definition: types_p.h:58
Field Definition for FIT Data Messages.
Definition: types_p.h:69
FitBaseType baseType
Base type for interpreting unknown fields.
Definition: types_p.h:72
quint8 number
Unique ID for the FIT field within a given FIT data message.
Definition: types_p.h:70
quint8 size
Size (in bytes) of the field.
Definition: types_p.h:71
FitBaseType
Garmin FIT FitBaseType type.
Definition: types.h:3388
MesgNum
Garmin FIT MesgNum type.
Definition: types.h:91
Architecture
Architecture Type for FIT Data Messages.
Definition: types_p.h:42
@ BigEndian
Little-endian byte ordering.

References DataDefinition::architecture, FieldDefinition::baseType, BigEndian, dataDefinitions, DeveloperFieldDefinition::devDataIndex, DataDefinition::developerFieldDefinitions, DataDefinition::fieldDefinitions, DeveloperFieldDefinition::fieldNumber, DataDefinition::globalMessageNumber, isDefinitionMessage(), FieldDefinition::number, DataDefinition::recordSize, DeveloperFieldDefinition::size, and FieldDefinition::size.

Here is the call graph for this function:

◆ parseFileHeader()

template<class T >
bool FitStreamReaderPrivate::parseFileHeader
protected

Reads and parses the FIT stream's file header.

Todo:
Provide, and document, a way for the caller to distingish errors from simply not-enough- bytes-yet, when false it returned.
Returns
true if the header was successfully read and parsed, false otherwise.
Todo:
set not-enough-bytes; ie might need to wait for more bytes.
Todo:
set invalid header size error; ie FIT stream is corrupt / invalid.
Todo:
set invalid header data type (must be ".FIT").
Todo:
set error, and return false here?

Definition at line 319 of file fitstreamreader.cpp.

320 {
321  Q_ASSERT(protocolVersion.isNull());
322  Q_ASSERT(profileVersion.isNull());
323 
324  // Read the header bytes.
325  const QByteArray header = readFileHeader<T>();
326  qDebug() << "Header size" << header.size() << "bytes";
327  if (header.isEmpty()) {
328  /// \todo set not-enough-bytes; ie might need to wait for more bytes.
329  qDebug() << "not enough bytes for header";
330  return false;
331  }
332  if (header.size() < 12) {
333  /// \todo set invalid header size error; ie FIT stream is corrupt / invalid.
334  qDebug() << "invalid header size";
335  return false;
336  }
337 
338  { // Protocol version is split into two parts: high 4 bits major, a low 4 bits minor.
339  const quint8 version = header.at(1);
340  protocolVersion = QVersionNumber(version >> 4, version & 0x0F);
341  qDebug() << "Protocol version" << protocolVersion;
342  }
343 
344  { // Profile version is major*100 + minor (ie minor could not be more than 99).
345  const quint16 version = qFromLittleEndian<quint16>(header.mid(2,2).data());
346  profileVersion = QVersionNumber(version/100, version%100);
347  qDebug() << "Profile version" << profileVersion;
348  }
349 
350  expectedDataSize = qFromLittleEndian<quint32>(header.mid(4,4).data());
351  qDebug() << "Data size" << expectedDataSize << "bytes";
352 
353  const QByteArray dataType = header.mid(8,4);
354  qDebug() << "Data type" << dataType;
355  if (dataType != QByteArray(".FIT")) {
356  /// \todo set invalid header data type (must be ".FIT").
357  return false;
358  }
359 
360  // Check the header's checksum (only present in 14+ byte headers, and even then may be 0x0000).
361  if (header.size() >= 14) {
362  const quint16 expectedChecksum = qFromLittleEndian<quint16>(data.mid(12,2).data());
363  if (expectedChecksum == 0x0000) {
364  qDebug() << "FIT file has (optional) checksum 0x0000; ignoring.";
365  } else {
366  const quint16 calculatedChecksum = fitChecksum(header.mid(0,12));
367  qDebug() << "Header checksum" << expectedChecksum << calculatedChecksum;
368  if (calculatedChecksum != expectedChecksum) {
369  qWarning() << "Checksum failure:" << calculatedChecksum << "!=" << expectedChecksum;
370  /// \todo set error, and return false here?
371  } else {
372  qDebug() << "Checkums match";
373  }
374  }
375  }
376  return true;
377 }
quint32 expectedDataSize
Total size, in bytes, expected to comprise the FIT file.
static quint16 fitChecksum(const QByteArray &data)
Calculates a checksum, as per the algorithm used by FIT file headers.
QVersionNumber profileVersion
Protocol version read from the parsed FIT file header.
QVersionNumber protocolVersion
Protocol version read from the parsed FIT file header.

References data, expectedDataSize, fitChecksum(), profileVersion, and protocolVersion.

Here is the call graph for this function:

◆ peekByte() [1/3]

template<>
quint8 FitStreamReaderPrivate::peekByte ( const int  pos) const
protected

Specialisation for reading from QByteArray objects.

Parameters
posThe position (relative to the current stream position) to peek.
Returns
the next pos'th byte, or 0 if not enough bytes were available.

Definition at line 566 of file fitstreamreader.cpp.

567 {
568  Q_ASSERT(device == nullptr);
569  return (data.size() > (dataOffset + pos)) ? data.at(dataOffset+pos) : 0;
570 }

References data, dataOffset, and device.

◆ peekByte() [2/3]

template<>
quint8 FitStreamReaderPrivate::peekByte ( const int  pos) const
protected

Specialisation for reading from QIODevice streams.

Parameters
posThe position (relative to the current stream position) to peek.
Returns
the next pos'th byte, or 0 if not enough bytes were available.

Definition at line 579 of file fitstreamreader.cpp.

580 {
581  Q_ASSERT(device != nullptr);
582  const QByteArray bytes = device->peek(1+pos);
583  return (bytes.size() > pos) ? bytes.at(pos) : 0;
584 }

References device.

◆ peekByte() [3/3]

template<class T >
FitStreamReaderPrivate::peekByte ( const int  pos = 0) const
protected

Peeks the next pos'th byte in the FIT stream.

If less than pos bytes are available, 0 will be returned. It is the caller's responsibility to first check that there are enough bytes availble (eg via bytesAvailable) before calling this, otherwise it would be impossible to distinguish between not-enough-bytes-available and reading a valid 0x00 byte.

Of course, we could provide a better error feedback mechanism, but as this is an internal private function, and all of our callers need to check for bytes first anyway, this is the more efficient pattern here.

Parameters
posThe position (relative to the current stream position) to peek.
Returns
the next pos'th byte, or 0 if not enough bytes were available.

◆ readBytes() [1/3]

template<>
QByteArray FitStreamReaderPrivate::readBytes ( const size_t  size)
protected

Specialisation for reading from QIODevice streams.

Parameters
sizeThe number of bytes to read.
Returns
the next size bytes, or an empty QDataArray if less than size bytes were available.

Definition at line 603 of file fitstreamreader.cpp.

604 {
605  Q_ASSERT(device == nullptr);
606  return ((data.size() - dataOffset) < size) ? QByteArray() : data.mid((dataOffset+=size)-size, size);
607 }

References data, dataOffset, and device.

◆ readBytes() [2/3]

template<>
QByteArray FitStreamReaderPrivate::readBytes ( const size_t  size)
protected

Specialisation for reading from QIODevice streams.

Parameters
sizeThe number of bytes to read.
Returns
the next size bytes, or an empty QDataArray if less than size bytes were available.

Definition at line 616 of file fitstreamreader.cpp.

617 {
618  Q_ASSERT(device != nullptr);
619  return (device->bytesAvailable() < size) ? QByteArray() : device->read(size);
620 }

References device.

◆ readBytes() [3/3]

template<class T >
FitStreamReaderPrivate::readBytes ( const size_t  size)
protected

Reads the next size bytes from the FIT stream.

Parameters
sizeThe number of bytes to read.
Returns
the next size bytes, or an empty QDataArray if less than size bytes were available.

◆ readFileHeader()

template<class T >
QByteArray FitStreamReaderPrivate::readFileHeader
protected

Reads all bytes of the FIT stream file header.

This function will first peek the header length (if available), and then read the entire header if (and only if) all header bytes are available.

Returns
the FIT file header, or an empty QByteArray if not enough bytes were available.

Definition at line 630 of file fitstreamreader.cpp.

631 {
632  // Return `n` bytes, where `n` is given by the first byte (ie a length-prefixed buffer).
633  return (bytesAvailable<T>()) ? readBytes<T>(peekByte<T>()) : QByteArray();
634 }

◆ readNextDataMessage()

template<class T >
AbstractDataMessage * FitStreamReaderPrivate::readNextDataMessage
protected

Reads up to, and including, the next FIT Data Message.

This function will continue reading the FIT stream until either no bytes are available, or a FIT Data Message has been located and parsed (or failed to be parsed). If (as expected) Definition Messages are found in the process, then they will be parse, and their definitions cached for interpreting future Data Messages.

Note
The caller takes ownership of the returned pointer (if not nullptr), and is responsible for deleting object when finished with.
Returns
the next FIT Data Message, or a nullptr if none found, or an error occurred.

Definition at line 649 of file fitstreamreader.cpp.

650 {
651  // If we haven't parsed the FIT File Header yet, do so now.
652  if ((protocolVersion.isNull() && (!parseFileHeader<T>()))) {
653  return nullptr;
654  }
655 
656  // Process all FIT Data Records until we get a FIT Data Message (or run out of bytes).
657  while (bytesAvailable<T>()) { // At least one byte, for the next data record header byte.
658  const quint8 recordHeader = peekByte<T>();
659  if (isDefinitionMessage(recordHeader)) {
660  if (!parseDefinitionMessage<T>()) return nullptr;
661  // Not returning here; we'll continue processing until we get a FIT Data Message.
662  } else return parseDataMessage<T>();
663  }
664  return nullptr;
665 }

References isDefinitionMessage(), and protocolVersion.

Here is the call graph for this function:

The documentation for this class was generated from the following files: