1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101

pub struct Crc16 {
    pub divisor: u16,
    pub initial_reminder: u16,
    pub table: Vec<u16>,
    pub reversed_input: bool,
    pub reverser_output: bool,
    pub xorout: u16
}

impl Crc16 {

    /// Precomputes table for CRC calculation
    ///
    /// *Note*: Calling calcuate CRC without having precomputed table will result
    /// in panic.
    pub fn create_table(&mut self) {
        for i in 0..256 {
            let mut value: u16 = i;
            value = value << 8;
            for _ in 0..8 {
                if (value & 0x8000) != 0 {
                    value = (value << 1) ^ self.divisor;
                } else {
                    value = value << 1;
                }
            }
            self.table.push(value);
        }
    }

    /// Calculates CRC16 value for given byte array
    ///
    /// # Arguments
    ///
    /// * `bytes` - A byte array whose value is being calculated.
    pub fn calculate(&self, bytes: &[u8]) -> u16 {
        self.calculate_rolling(bytes, self.initial_reminder)
    }

    /// Calculates CRC16 value for given byte array, but assumes 
    /// calculation is resumed from previous state (multiple_parts)
    ///
    /// # Arguments
    ///
    /// * `bytes` - A byte array whose value is being calculated.
    /// * `current_value` - A CRC16 value obtained when calculating CRC16 of 
    /// previous part.
    pub fn calculate_rolling(&self, bytes: &[u8], current_value: u16) -> u16 {
         assert_eq!(self.table.is_empty(), false, "Table was not initialized.");
         assert_eq!(self.table.len(), 256, "Table size was incorrect.");

         let mut value: u16 = current_value;
         for &i in bytes.iter() {
             let current_byte: u8 = if self.reversed_input {
                 reflect(i as u16, 8) as u8
             }
             else {
                 i
             };
             value = self.table[((value >> 8 ) ^ current_byte as u16) as usize] ^ (value << 8);
         }
         
         if self.reverser_output {
             reflect(value ^ self.xorout, 16)
         }
         else {
             value ^ self.xorout
         }
    }

    /// Checks if byte array has valid CRC appended
    /// are continuing calculation from previous state (multiple_parts)
    ///
    /// # Arguments
    ///
    /// * `bytes` - A byte array whose value is being checked.
    ///
    /// *Note*: Assuming that last two bytes in array are CRC16 value that 
    /// was appended, this only works if whole data we are checking is in byte
    /// array. For larger files we can check validity by calculating CRC value
    /// again and checking if it is 0.
    pub fn check(&self, bytes: &[u8]) -> bool {
        return self.calculate(bytes) == 0u16;
    }        

}

fn reflect(data: u16, bit_size: u8) -> u16
{
    let mut reflection: u16 = 0x0000;

    for i in 0..bit_size {
        if (data >> i) & 0x01 == 1 {
            reflection |= 1 << ((bit_size - 1) - i);
        }
    }

    reflection
}