/** * @param fitFile * @return */ public static boolean isValid(final Path fitFile) { final InputStream in; try { in = Files.newInputStream(fitFile); } catch (final IOException | SecurityException e) { logger.info("Could not open fit file.", e); return false; } final Header header = new Header(); try { header.readHeader(in); } catch (final IOException e) { logger.info("Error while reading fit file header.", e); return false; } if (!header.isValid()) { logger.info("Fit file header is not valid."); return false; } final byte[] data = new byte[header.getDataSize() + 2]; try { in.read(data); } catch (final IOException e) { logger.info("Error while reading fit records and CRC.", e); return false; } final CRC crc = new CRC(); crc.update(header.getHeader(), header.getHeaderSize()); crc.update(data); if (crc.getValue() != 0x0000) { logger.info("Fit file CRC error."); return false; } return true; }
/** * @param in * @return * @throws IOException */ public boolean read(InputStream in) throws IOException { // Read header. final Header header = new Header(); header.readHeader(in); if (!header.isValid()) { logger.error("Fit file header is not valid."); return false; } crc.reset(); readBytes = 0; stop = false; for (int i = 0; i < header.getHeaderSize(); i++) { crc.update(header.getHeader()[i]); } dispatcher.onHeader(header); // Read data records. final DefinitionMessage[] definitions = new DefinitionMessage[MAX_LOCAL_MESSAGE_NUMS]; final int dataSize = header.getDataSize(); int data = -1; while (readBytes < dataSize && (data = in.read()) > -1) { // Record header byte was read. readBytes++; final int recordType = data & RECORD_HEADER_TYPE_MASK; if (recordType == DEFINITION_MESSAGE) { final DefinitionMessage defMsg = new DefinitionMessage((byte) data); readDefinitionMessage(defMsg, in); // Store new definition message. definitions[defMsg.getLocalMessageType()] = defMsg; dispatcher.onDefinitionMessage(defMsg); } else { final DataMessage msg; if (recordType == COMPRESSED_TIMESTAMP) { final int timeOffset = data & COMPRESSED_TIMESTAMP_MASK; timestampOffset.setOffset(timeOffset); msg = new DataMessage((byte) data, timestampOffset.getTimestamp()); } else if (recordType == DATA_MESSAGE) { msg = new DataMessage((byte) data); } else { logger.error( "Unknown message header type. message header: 0x{}", Integer.toHexString(data)); return false; } final DefinitionMessage defMsg = definitions[msg.getLocalMessageType()]; if (defMsg == null) { logger.error( "Definition message does not exists. message header: {}, read: {} bytes", data, header.getHeaderSize() + readBytes); return false; } readDataMessage(defMsg, msg, in); dispatcher.onDataMessage(defMsg, msg); } if (stop) { logger.info("Stop reading. read: {} bytes", header.getHeaderSize() + readBytes); return false; } } if (readBytes != dataSize) { logger.error( "A mismatch between read message size and defined size of the header. read: {} bytes, defined: {} bytes", readBytes, dataSize); return false; } // read crc(2 bytes). for (int i = 0; i < 2; i++) { final int d = in.read(); if (d < 0) { logger.error( "Unexpected EOF while reading crc. read: {} bytes", header.getHeaderSize() + readBytes + i + 1); return false; } crc.update((byte) d); } if (crc.getValue() != 0) { logger.error("Fit file CRC error."); return false; } // check EOF. if (in.read() > 0) { logger.error( "Unexpected data exists after crc. read: {} bytes", header.getHeaderSize() + readBytes + 2); return false; } return true; }