fit-file-parser 4.0.2 → 5.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -31,23 +31,23 @@ class FitParser {
31
31
  });
32
32
  }
33
33
  parse(content, callback) {
34
- var _a;
34
+ var _a, _b;
35
35
  const blob = content instanceof ArrayBuffer
36
36
  ? new Uint8Array(content)
37
37
  : new Uint8Array(content.buffer, content.byteOffset, content.byteLength);
38
38
  const dataView = new DataView(blob.buffer, blob.byteOffset, blob.byteLength);
39
39
  if (blob.length < 12) {
40
40
  callback('File to small to be a FIT file', undefined);
41
- if (!this.options.force) {
42
- return;
43
- }
41
+ return;
44
42
  }
45
43
  const headerLength = blob[0];
46
44
  if (headerLength !== 14 && headerLength !== 12) {
47
45
  callback('Incorrect header size', undefined);
48
- if (!this.options.force) {
49
- return;
50
- }
46
+ return;
47
+ }
48
+ if (blob.length < headerLength) {
49
+ callback('File to small to be a FIT file', undefined);
50
+ return;
51
51
  }
52
52
  let fileTypeString = '';
53
53
  for (let i = 8; i < 12; i++) {
@@ -55,29 +55,33 @@ class FitParser {
55
55
  }
56
56
  if (fileTypeString !== '.FIT') {
57
57
  callback('Missing \'.FIT\' in header', undefined);
58
- if (!this.options.force) {
59
- return;
60
- }
58
+ return;
61
59
  }
62
60
  if (headerLength === 14 && !this.options.force) {
63
61
  const crcHeader = blob[12] + (blob[13] << 8);
64
62
  const crcHeaderCalc = (0, binary_js_1.calculateCRC)(blob, 0, 12);
65
- if (crcHeader !== crcHeaderCalc) {
66
- // callback('Header CRC mismatch', {});
67
- // TODO: fix Header CRC check
63
+ if (crcHeader !== 0 && crcHeader !== crcHeaderCalc) {
64
+ callback('Header CRC mismatch', undefined);
68
65
  return;
69
66
  }
70
67
  }
71
68
  const protocolVersion = blob[1];
72
69
  const profileVersion = blob[2] + (blob[3] << 8);
73
- const dataLength = blob[4] + (blob[5] << 8) + (blob[6] << 16) + (blob[7] << 24);
70
+ const dataLength = dataView.getUint32(4, true);
74
71
  const crcStart = dataLength + headerLength;
72
+ if (crcStart > blob.length) {
73
+ callback('File data exceeds input length', undefined);
74
+ return;
75
+ }
76
+ if (!this.options.force && crcStart + 2 > blob.length) {
77
+ callback('File CRC missing', undefined);
78
+ return;
79
+ }
75
80
  if (!this.options.force) {
76
81
  const crcFile = blob[crcStart] + (blob[crcStart + 1] << 8);
77
- const crcFileCalc = (0, binary_js_1.calculateCRC)(blob, headerLength === 12 ? 0 : headerLength, crcStart);
82
+ const crcFileCalc = (0, binary_js_1.calculateCRC)(blob, 0, crcStart);
78
83
  if (crcFile !== crcFileCalc) {
79
- // callback('File CRC mismatch', {});
80
- // TODO: fix File CRC check
84
+ callback('File CRC mismatch', undefined);
81
85
  return;
82
86
  }
83
87
  }
@@ -85,6 +89,7 @@ class FitParser {
85
89
  profileVersion,
86
90
  protocolVersion,
87
91
  };
92
+ const messages = {};
88
93
  let sessions = [];
89
94
  let laps = [];
90
95
  const records = [];
@@ -107,6 +112,7 @@ class FitParser {
107
112
  const tank_updates = [];
108
113
  const tank_summaries = [];
109
114
  const jumps = [];
115
+ const sets = [];
110
116
  const splits = [];
111
117
  const split_summaries = [];
112
118
  const time_in_zone = [];
@@ -115,14 +121,20 @@ class FitParser {
115
121
  let loopIndex = headerLength;
116
122
  const messageTypes = [];
117
123
  const developerFields = [];
124
+ const decoderState = {};
118
125
  const isModeCascade = this.options.mode === 'cascade';
119
126
  const isCascadeNeeded = isModeCascade || this.options.mode === 'both';
120
127
  let startDate;
121
128
  let lastStopTimestamp;
122
129
  let pausedTime = 0;
123
130
  while (loopIndex < crcStart) {
124
- const { nextIndex, messageType, message } = (0, binary_js_1.readRecord)(blob, messageTypes, developerFields, loopIndex, this.options, startDate, pausedTime, dataView);
131
+ const { nextIndex, messageType, message } = (0, binary_js_1.readRecord)(blob, messageTypes, developerFields, loopIndex, this.options, startDate, pausedTime, dataView, decoderState);
125
132
  loopIndex = nextIndex;
133
+ if (messageType !== ''
134
+ && messageType !== 'definition'
135
+ && message !== undefined) {
136
+ ((_a = messages[messageType]) !== null && _a !== void 0 ? _a : (messages[messageType] = [])).push(message);
137
+ }
126
138
  switch (messageType) {
127
139
  case 'lap':
128
140
  laps.push(message);
@@ -156,8 +168,10 @@ class FitParser {
156
168
  case 'record':
157
169
  if (!startDate) {
158
170
  startDate = message.timestamp;
159
- message.elapsed_time = 0;
160
- message.timer_time = 0;
171
+ if (this.options.elapsedRecordField) {
172
+ message.elapsed_time = 0;
173
+ message.timer_time = 0;
174
+ }
161
175
  }
162
176
  records.push(message);
163
177
  break;
@@ -210,6 +224,9 @@ class FitParser {
210
224
  case 'jump':
211
225
  jumps.push(message);
212
226
  break;
227
+ case 'set':
228
+ sets.push(message);
229
+ break;
213
230
  case 'split':
214
231
  splits.push(message);
215
232
  break;
@@ -250,15 +267,17 @@ class FitParser {
250
267
  fitObj.time_in_zone = time_in_zone;
251
268
  fitObj.activity_metrics = activity_metrics;
252
269
  fitObj.user_metrics = user_metrics;
270
+ fitObj.messages = messages;
253
271
  if (isCascadeNeeded) {
254
272
  laps = (0, helper_js_1.mapDataIntoLap)(laps, 'records', records);
255
273
  laps = (0, helper_js_1.mapDataIntoLap)(laps, 'lengths', lengths);
256
274
  sessions = (0, helper_js_1.mapDataIntoSession)(sessions, laps);
257
- fitObj.activity = Object.assign(Object.assign({}, ((_a = fitObj.activity) !== null && _a !== void 0 ? _a : {})), { // ugly but we assume the activity was parsed correctly with all other members correctly
275
+ fitObj.activity = Object.assign(Object.assign({}, ((_b = fitObj.activity) !== null && _b !== void 0 ? _b : {})), { // ugly but we assume the activity was parsed correctly with all other members correctly
258
276
  sessions,
259
277
  events,
260
278
  hrv,
261
279
  device_infos, developer_data_ids: applications, field_descriptions: fieldDescriptions, sports,
280
+ sets,
262
281
  splits,
263
282
  split_summaries });
264
283
  }
@@ -272,6 +291,7 @@ class FitParser {
272
291
  fitObj.developer_data_ids = applications;
273
292
  fitObj.field_descriptions = fieldDescriptions;
274
293
  fitObj.hrv = hrv;
294
+ fitObj.sets = sets;
275
295
  }
276
296
  callback(undefined, fitObj);
277
297
  }
package/dist/cjs/fit.d.ts CHANGED
@@ -1,8 +1,11 @@
1
1
  import type { FitOptions, MesgNum } from './fit_types.js';
2
+ export type MessageName = Exclude<MesgNum, number | 'definition'>;
2
3
  export interface FieldDefinition {
3
4
  type: string | number;
5
+ rawType?: string | number;
4
6
  fDefNo: number;
5
7
  size: number;
8
+ array?: boolean;
6
9
  endianAbility: boolean;
7
10
  littleEndian: boolean;
8
11
  baseTypeNo: number;
@@ -10,6 +13,7 @@ export interface FieldDefinition {
10
13
  dataType: string;
11
14
  scale?: number | null;
12
15
  offset?: number;
16
+ units?: string;
13
17
  requiresBoundedDataView?: boolean;
14
18
  developerDataIndex?: number;
15
19
  isDeveloperField?: boolean;
@@ -17,22 +21,26 @@ export interface FieldDefinition {
17
21
  export interface MessageObject {
18
22
  field: string;
19
23
  type: string;
24
+ baseType?: string;
25
+ array?: boolean;
20
26
  scale: number | null;
21
27
  offset: number;
22
28
  units: string;
23
29
  }
24
30
  export interface Message {
25
- name: MesgNum;
31
+ name: MessageName;
26
32
  [fieldId: number]: MessageObject;
27
33
  }
28
34
  export interface FitType {
29
35
  scConst: number;
30
36
  options: FitOptions;
31
- messages: {
32
- [messageId: number]: Message;
33
- };
34
- types: {
35
- [typeName: string]: Record<number, string | number>;
36
- };
37
+ messages: Record<number, Message>;
38
+ types: Record<string, Record<number, string | number>>;
37
39
  }
40
+ /**
41
+ * Garmin fields observed in the external FIT corpus but absent from the pinned
42
+ * public SDK profile. These additions may not replace standard SDK fields.
43
+ */
44
+ export declare const FIT_VENDOR_MESSAGE_EXTENSIONS: Record<number, Message>;
45
+ export declare const FIT_VENDOR_TYPE_EXTENSIONS: Record<string, Record<number, string>>;
38
46
  export declare const FIT: FitType;