lib/fit4ruby/FitFile.rb in fit4ruby-3.0.0 vs lib/fit4ruby/FitFile.rb in fit4ruby-3.1.0

- old
+ new

@@ -1,18 +1,20 @@ #!/usr/bin/env ruby -w # encoding: UTF-8 # # = FitFile.rb -- Fit4Ruby - FIT file processing library for Ruby # -# Copyright (c) 2014, 2015 by Chris Schlaeger <cs@taskjuggler.org> +# Copyright (c) 2014, 2015, 2016, 2017, 2018 +# by Chris Schlaeger <cs@taskjuggler.org> # # This program is free software; you can redistribute it and/or modify # it under the terms of version 2 of the GNU General Public License as # published by the Free Software Foundation. # require 'fit4ruby/Log' +require 'fit4ruby/CRC16' require 'fit4ruby/FileNameCoder' require 'fit4ruby/FitHeader' require 'fit4ruby/FitFileEntity' require 'fit4ruby/FitRecord' require 'fit4ruby/FitFilter' @@ -22,10 +24,12 @@ module Fit4Ruby class FitFile + include CRC16 + def initialize() @header = nil end def read(file_name, filter = nil) @@ -41,14 +45,19 @@ begin while !io.eof? offset = io.pos header = FitHeader.read(io) - header.check - check_crc(io, io.pos, offset + header.end_pos) + # If the header has a CRC the header is not included in the + # checksumed bytes. Otherwise it is included. + check_crc(io, header.has_crc? ? header.header_size : 0, + offset + header.end_pos) + # Rewind back to the beginning of the data right after the header. + io.seek(header.header_size) + entity = FitFileEntity.new # This Array holds the raw data of the records that may be needed to # dump a human readable form of the FIT file. records = [] # This hash will hold a counter for each record type. The counter is @@ -84,10 +93,11 @@ begin # Create a header object, but don't yet write it into the file. header = FitHeader.new start_pos = header.header_size + # Move the pointer behind the header section. io.seek(start_pos) id_mapper = FitMessageIdMapper.new top_level_record.write(io, id_mapper) end_pos = io.pos @@ -95,11 +105,10 @@ crc = write_crc(io, start_pos, end_pos) # Complete the data of the header section and write it at the start of # the file. header.data_size = end_pos - start_pos - header.crc = crc io.seek(0) header.write(io) ensure io.close end @@ -111,48 +120,15 @@ crc = compute_crc(io, start_pos, end_pos) # Read the 2 CRC bytes from the end of the file io.seek(end_pos) crc_ref = io.readbyte.to_i | (io.readbyte.to_i << 8) - io.seek(start_pos) unless crc == crc_ref - Log.fatal "Checksum error in file '#{@file_name}'. " + + Log.error "Checksum error of segment #{start_pos} to #{end_pos} " + + "in file '#{@file_name}'. " + "Computed 0x#{"%04X" % crc} instead of 0x#{"%04X" % crc_ref}." end - end - - def write_crc(io, start_pos, end_pos) - # Compute the checksum over the data section of the file and append it - # to the file. Ideally, we should compute the CRC from data in memory - # instead of the file data. - crc = compute_crc(io, start_pos, end_pos) - io.seek(end_pos) - BinData::Uint16le.new(crc).write(io) - - crc - end - - def compute_crc(io, start_pos, end_pos) - crc_table = [ - 0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401, - 0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400 - ] - - io.seek(start_pos) - - crc = 0 - while io.pos < end_pos - byte = io.readbyte - - 0.upto(1) do |i| - tmp = crc_table[crc & 0xF] - crc = (crc >> 4) & 0x0FFF - crc = crc ^ tmp ^ crc_table[(byte >> (4 * i)) & 0xF] - end - end - - crc end def dump_records(records) # For each message number we keep a count for how often we already had # this kind of message.