From 25fad21108d14cda8bc53febe9e26410c540d08e Mon Sep 17 00:00:00 2001 From: Paul Kraft Date: Thu, 20 Jul 2023 14:34:00 +0200 Subject: [PATCH 1/4] CRC: Implement package with calculator, multiple predefined standards and tests --- .swiftpm/CRC.xctestplan | 24 + .../contents.xcworkspacedata | 7 + .../UserInterfaceState.xcuserstate | Bin 0 -> 52016 bytes .../xcode/xcshareddata/xcschemes/CRC.xcscheme | 97 ++ .../xcschemes/xcschememanagement.plist | 100 ++ Package.swift | 24 + .../UserInterfaceState.xcuserstate | Bin 0 -> 13702 bytes .../xcschemes/xcschememanagement.plist | 16 - Source Files/CRC.swift | 47 - Source Files/CRC16.swift | 60 -- Source Files/CRC32.swift | 59 -- Source Files/CRC8.swift | 58 -- Sources/CRC+Verify.swift | 65 ++ Sources/CRC.swift | 112 +++ Sources/CRC16.swift | 37 + Sources/CRC32.swift | 25 + Sources/CRC64.swift | 16 + Sources/CRC8.swift | 24 + Sources/CRCCalculator.swift | 73 ++ Tests/CRC16Tests.swift | 950 ++++++++++++++++++ Tests/CRC32Tests.swift | 427 ++++++++ Tests/CRC64Tests.swift | 108 ++ Tests/CRC8Tests.swift | 430 ++++++++ Tests/CRCTestCase.swift | 101 ++ 24 files changed, 2620 insertions(+), 240 deletions(-) create mode 100644 .swiftpm/CRC.xctestplan create mode 100644 .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata create mode 100644 .swiftpm/xcode/package.xcworkspace/xcuserdata/pauljohanneskraft.xcuserdatad/UserInterfaceState.xcuserstate create mode 100644 .swiftpm/xcode/xcshareddata/xcschemes/CRC.xcscheme create mode 100644 .swiftpm/xcode/xcuserdata/pauljohanneskraft.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100644 Package.swift create mode 100644 Playgrounds/CRC8.playground/playground.xcworkspace/xcuserdata/pauljohanneskraft.xcuserdatad/UserInterfaceState.xcuserstate delete mode 100644 Playgrounds/CRC8.playground/xcuserdata/nasir.xcuserdatad/xcschemes/xcschememanagement.plist delete mode 100644 Source Files/CRC.swift delete mode 100644 Source Files/CRC16.swift delete mode 100644 Source Files/CRC32.swift delete mode 100644 Source Files/CRC8.swift create mode 100644 Sources/CRC+Verify.swift create mode 100644 Sources/CRC.swift create mode 100644 Sources/CRC16.swift create mode 100644 Sources/CRC32.swift create mode 100644 Sources/CRC64.swift create mode 100644 Sources/CRC8.swift create mode 100644 Sources/CRCCalculator.swift create mode 100644 Tests/CRC16Tests.swift create mode 100644 Tests/CRC32Tests.swift create mode 100644 Tests/CRC64Tests.swift create mode 100644 Tests/CRC8Tests.swift create mode 100644 Tests/CRCTestCase.swift diff --git a/.swiftpm/CRC.xctestplan b/.swiftpm/CRC.xctestplan new file mode 100644 index 0000000..c220384 --- /dev/null +++ b/.swiftpm/CRC.xctestplan @@ -0,0 +1,24 @@ +{ + "configurations" : [ + { + "id" : "14319F7F-D4ED-4C2E-B2D4-97FAE7C6F388", + "name" : "Test Scheme Action", + "options" : { + + } + } + ], + "defaultOptions" : { + + }, + "testTargets" : [ + { + "target" : { + "containerPath" : "container:", + "identifier" : "CRCTests", + "name" : "CRCTests" + } + } + ], + "version" : 1 +} diff --git a/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/.swiftpm/xcode/package.xcworkspace/xcuserdata/pauljohanneskraft.xcuserdatad/UserInterfaceState.xcuserstate b/.swiftpm/xcode/package.xcworkspace/xcuserdata/pauljohanneskraft.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000000000000000000000000000000000000..803276ee5aab32a236c594d7f43fd9fba92111c1 GIT binary patch literal 52016 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 XNS*%QLsMGX|8n%!|K + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.swiftpm/xcode/xcuserdata/pauljohanneskraft.xcuserdatad/xcschemes/xcschememanagement.plist b/.swiftpm/xcode/xcuserdata/pauljohanneskraft.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..4d0d115 --- /dev/null +++ b/.swiftpm/xcode/xcuserdata/pauljohanneskraft.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,100 @@ + + + + + SchemeUserState + + CRC.xcscheme_^#shared#^_ + + orderHint + 1 + + CRC16 (Playground) 1.xcscheme + + isShown + + orderHint + 1 + + CRC16 (Playground) 2.xcscheme + + isShown + + orderHint + 2 + + CRC16 (Playground).xcscheme + + isShown + + orderHint + 2 + + CRC32 (Playground) 1.xcscheme + + isShown + + orderHint + 4 + + CRC32 (Playground) 2.xcscheme + + isShown + + orderHint + 5 + + CRC32 (Playground).xcscheme + + isShown + + orderHint + 3 + + CRC8 (Playground) 1.xcscheme + + isShown + + orderHint + 7 + + CRC8 (Playground) 2.xcscheme + + isShown + + orderHint + 8 + + CRC8 (Playground).xcscheme + + isShown + + orderHint + 4 + + crc-swift-Package.xcscheme_^#shared#^_ + + orderHint + 0 + + + SuppressBuildableAutocreation + + CRC + + primary + + + CRCTests + + primary + + + crc-swift + + primary + + + + + diff --git a/Package.swift b/Package.swift new file mode 100644 index 0000000..d48198c --- /dev/null +++ b/Package.swift @@ -0,0 +1,24 @@ +// swift-tools-version: 5.4 + +import PackageDescription + +let package = Package( + name: "CRC", + products: [ + .library( + name: "CRC", + targets: ["CRC"] + ), + ], + targets: [ + .target( + name: "CRC", + path: "Sources" + ), + .testTarget( + name: "CRCTests", + dependencies: ["CRC"], + path: "Tests" + ), + ] +) diff --git a/Playgrounds/CRC8.playground/playground.xcworkspace/xcuserdata/pauljohanneskraft.xcuserdatad/UserInterfaceState.xcuserstate b/Playgrounds/CRC8.playground/playground.xcworkspace/xcuserdata/pauljohanneskraft.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000000000000000000000000000000000000..e7c6a31ec16e87ac70034a6b809eb595e0f8fa64 GIT binary patch literal 13702 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 literal 0 HcmV?d00001 diff --git a/Playgrounds/CRC8.playground/xcuserdata/nasir.xcuserdatad/xcschemes/xcschememanagement.plist b/Playgrounds/CRC8.playground/xcuserdata/nasir.xcuserdatad/xcschemes/xcschememanagement.plist deleted file mode 100644 index adc4499..0000000 --- a/Playgrounds/CRC8.playground/xcuserdata/nasir.xcuserdatad/xcschemes/xcschememanagement.plist +++ /dev/null @@ -1,16 +0,0 @@ - - - - - SchemeUserState - - CRC8 (Playground).xcscheme - - isShown - - orderHint - 0 - - - - diff --git a/Source Files/CRC.swift b/Source Files/CRC.swift deleted file mode 100644 index f325dc3..0000000 --- a/Source Files/CRC.swift +++ /dev/null @@ -1,47 +0,0 @@ -// -// CRC.swift -// -// Copyright © 2020 QuickBird Studios. All rights reserved. -// - -import Foundation - -public protocol CRC { - associatedtype Size - - var currentValue: Size { get } - - func append(_ bytes: [UInt8]) - - func reset() -} - -extension CRC { - public func append(_ byte: UInt8) { - append([byte]) - } - - public func append(_ integer: T) { - append(integer.bigEndianBytes) - } - - public func append(_ floatingPoint: T) { - append(floatingPoint.bigEndianBytes) - } -} - -// MARK: - Convenience Extension Methods - -extension FixedWidthInteger { - public var bigEndianBytes: [UInt8] { - [UInt8](withUnsafeBytes(of: self.bigEndian) { Data($0) }) - } -} - -// `BinaryFloatingPoint` conforms to 754-2008 - IEEE Standard for Floating-Point Arithmetic (https://ieeexplore.ieee.org/document/4610935) -// If you target system is using a different floating point representation, you need to adapt accordingly -extension BinaryFloatingPoint { - public var bigEndianBytes: [UInt8] { - [UInt8](withUnsafeBytes(of: self) { Data($0) }).reversed() - } -} diff --git a/Source Files/CRC16.swift b/Source Files/CRC16.swift deleted file mode 100644 index 1cab333..0000000 --- a/Source Files/CRC16.swift +++ /dev/null @@ -1,60 +0,0 @@ -// -// CRC16.swift -// -// Copyright © 2020 QuickBird Studios. All rights reserved. -// - -import Foundation - -/// Class to conveniently calculate CRC-16. It uses the CRC16-CCITT polynomial (0x1021) by default -public class CRC16: CRC { - - /// The table that stores the precomputed remainders for all possible divisions for 1 byte - /// This table is used as a lookup (to speed up the calculation) - public let lookupTable: [UInt16] - - private(set) public var currentValue: UInt16 = 0 - - /// Creates the instance for calculating CRC - /// - Parameter polynomial: The polynomial to use. It uses CRC16-CCITT's polynomial (0x1021) by default - public init(polynomial: UInt16 = 0x1021) { - /// Generates the lookup table (make sure to generate it only once) - self.lookupTable = (0...255).map { Self.crc16(for: UInt8($0), polynomial: polynomial) } - } - - public func append(_ bytes: [UInt8]) { - currentValue = crc16(for: bytes, initialValue: currentValue) - } - - public func reset() { - currentValue = 0 - } -} - -/// Same code as the blog article -extension CRC16 { - /// Caculates CRC-16 of an array of Bytes (UInt8) - private func crc16(for inputs: [UInt8], initialValue: UInt16 = 0) -> UInt16 { - inputs.reduce(initialValue) { remainder, byte in - let bigEndianInput = UInt16(byte).bigEndian - let index = (bigEndianInput ^ remainder) >> 8 - return lookupTable[Int(index)] ^ (remainder << 8) - } - } - - /// Calculates the CRC-16 of 1 Byte - private static func crc16(for input: UInt8, polynomial: UInt16) -> UInt16 { - var result = UInt16(input).bigEndian - for _ in 0..<8 { - let isMostSignificantBitOne = result & 0x8000 != 0 - - result = result << 1 - - if isMostSignificantBitOne { - result = result ^ polynomial - } - } - - return result - } -} diff --git a/Source Files/CRC32.swift b/Source Files/CRC32.swift deleted file mode 100644 index 72da711..0000000 --- a/Source Files/CRC32.swift +++ /dev/null @@ -1,59 +0,0 @@ -// -// CRC32.swift -// -// Copyright © 2020 QuickBird Studios. All rights reserved. -// - -import Foundation - -/// Class to conveniently calculate CRC-32 It uses the CRC32 polynomial (0x04C11DB7) by default -public class CRC32: CRC { - - /// The table that stores the precomputed remainders for all possible divisions for 1 byte - /// This table is used as a lookup (to speed up the calculation) - public let lookupTable: [UInt32] - - private(set) public var currentValue: UInt32 = 0 - - /// Creates the instance for calculating CRC - /// - Parameter polynomial: The polynomial to use. It uses CRC32's polynomial (0x04C11DB7) by default - public init(polynomial: UInt32 = 0x04C11DB7) { - /// Generates the lookup table (make sure to generate it only once) - self.lookupTable = (0...255).map { Self.crc32(for: UInt8($0), polynomial: polynomial) } - } - - public func append(_ bytes: [UInt8]) { - currentValue = crc32(for: bytes, initialValue: currentValue) - } - - public func reset() { - currentValue = 0 - } -} - -extension CRC32 { - /// Caculates CRC-32 of an array of Bytes (UInt8) - private func crc32(for inputs: [UInt8], initialValue: UInt32 = 0) -> UInt32 { - inputs.reduce(initialValue) { remainder, byte in - let bigEndianInput = UInt32(byte).bigEndian - let index = (bigEndianInput ^ remainder) >> 24 - return lookupTable[Int(index)] ^ (remainder << 8) - } - } - - /// Calculates the CRC-32 of 1 Byte - private static func crc32(for input: UInt8, polynomial: UInt32) -> UInt32 { - var result = UInt32(input).bigEndian - for _ in 0..<8 { - let isMostSignificantBitOne = result & 0x80000000 != 0 - - result = result << 1 - - if isMostSignificantBitOne { - result = result ^ polynomial - } - } - - return result - } -} diff --git a/Source Files/CRC8.swift b/Source Files/CRC8.swift deleted file mode 100644 index 0bf5ccd..0000000 --- a/Source Files/CRC8.swift +++ /dev/null @@ -1,58 +0,0 @@ -// -// CRC8.swift -// -// Copyright © 2020 QuickBird Studios. All rights reserved. -// - -import Foundation - -/// Class to conveniently calculate CRC-8. It uses the CRC8-Bluetooth polynomial (0xA7) by default -public class CRC8: CRC { - - /// The table that stores the precomputed remainders for all possible divisions for 1 byte - /// This table is used as a lookup (to speed up the calculation) - public let lookupTable: [UInt8] - - private(set) public var currentValue: UInt8 = 0 - - /// Creates the instance for calculating CRC - /// - Parameter polynomial: The polynomial to use. It uses CRC8-Bluetooth's polynomial (0xA7) by default - public init(polynomial: UInt8 = 0xA7) { - /// Generates the lookup table (make sure to generate it only once) - self.lookupTable = (0...255).map { Self.CRC8(for: UInt8($0), polynomial: polynomial) } - } - - public func append(_ bytes: [UInt8]) { - currentValue = CRC8(for: bytes, initialValue: currentValue) - } - - public func reset() { - currentValue = 0 - } -} - -/// Same code as the blog article -extension CRC8 { - /// Caculates CRC-8 of an array of Bytes (UInt8) - private func CRC8(for inputs: [UInt8], initialValue: UInt8 = 0) -> UInt8 { - inputs.reduce(initialValue) { remainder, byte in - let index = byte ^ remainder - return lookupTable[Int(index)] - } - } - - /// Calculates the CRC-8 of 1 Byte - private static func CRC8(for input: UInt8, polynomial: UInt8) -> UInt8 { - var result = input - for _ in 0..<8 { - let isMostSignificantBitOne = result & 0x80 != 0 - - result = result << 1 - if isMostSignificantBitOne { - result = result ^ polynomial - } - } - - return result - } -} diff --git a/Sources/CRC+Verify.swift b/Sources/CRC+Verify.swift new file mode 100644 index 0000000..95c1dd3 --- /dev/null +++ b/Sources/CRC+Verify.swift @@ -0,0 +1,65 @@ +// +// File.swift +// +// +// Created by Paul Kraft on 17.07.23. +// + +import Foundation + +public struct VerificationError: Error, CustomStringConvertible { + + public let actualValue: Value + public let expectedValue: Value + + public var description: String { + "\(String(describing: Self.self))(expected: 0x\(expectedValue.hex), actual: 0x\(actualValue.hex))" + } + +} + +extension CRC { + + public func verify>(_ expectedValue: Value, for bytes: S) throws { + let actualValue = calculate(for: bytes) + guard expectedValue == actualValue else { + throw VerificationError( + actualValue: actualValue, + expectedValue: expectedValue + ) + } + } + +} + +extension CRCCalculator { + + public func verify(_ expectedValue: Value) throws { + let actualValue = finalValue + guard expectedValue == actualValue else { + throw VerificationError( + actualValue: actualValue, + expectedValue: expectedValue + ) + } + } + +} + +extension FixedWidthInteger { + + internal var hex: String { + withUnsafeBytes(of: bigEndian) { $0.hex } + } + +} + +extension Sequence { + + internal var hex: String { + self + .map { String(format: "%02hhX", $0) } + .joined() + } + +} diff --git a/Sources/CRC.swift b/Sources/CRC.swift new file mode 100644 index 0000000..b1dc76d --- /dev/null +++ b/Sources/CRC.swift @@ -0,0 +1,112 @@ +// +// CRC.swift +// +// Copyright © 2020 QuickBird Studios. All rights reserved. +// + +import Foundation + +public struct CRC { + + // MARK: Stored Properties + + public let initialValue: Value + public let refIn: Bool + public let refOut: Bool + public let xorOut: Value + + public let lookupTable: [Value] + + // MARK: Initialization + + public init( + polynomial: Value, + initialValue: Value = 0, + refIn: Bool = false, + refOut: Bool = false, + xorOut: Value = 0 + ) { + self.initialValue = refIn ? initialValue.reversed : initialValue + self.refIn = refIn + self.refOut = refOut + self.xorOut = xorOut + + let indices = UInt8.min...UInt8.max + self.lookupTable = [Value](unsafeUninitializedCapacity: indices.count) { pointer, initializedCapacity in + var result: Value = 0 + if refIn { + let reversedPolynomial = polynomial.reversed + for index in indices { + result = Value(index).littleEndian + for _ in 0..> 1) ^ reversedPolynomial + : (result >> 1) + } + pointer[Int(index)] = result + } + } else { + let mostSignificantBitOne: Value = (1 << (Value.bitWidth - 1)) + for index in indices { + result = Value(index).bigEndian + for _ in 0..>(for bytes: S, in value: inout Value) { + if refIn { + for byte in bytes { + let input = Value(byte).littleEndian + let index = (input ^ value) & 0xFF + value = lookupTable[Int(index)] ^ (value >> 8) + } + } else { + let bitWidthOverByteWidth = Value.bitWidth - 8 + for byte in bytes { + let input = Value(byte).bigEndian + let index = (input ^ value) >> bitWidthOverByteWidth + value = lookupTable[Int(index)] ^ (value << 8) + } + } + } + + public func complete(_ value: inout Value) { + value ^= xorOut + } + + public func calculate>(for bytes: S) -> Value { + var value = initialValue + calculate(for: bytes, in: &value) + complete(&value) + return value + } + +} + +extension FixedWidthInteger { + + internal var reversed: Self { + let bitWidth = bitWidth + var result: Self = 0 + + for bitIndex in 0.. + +extension CRC16 { + + public static let a = Self(polynomial: 0x1021, initialValue: 0xC6C6, refIn: true, refOut: true) + public static let arc = Self(polynomial: 0x8005, refIn: true, refOut: true) + public static let aug_ccitt = Self(polynomial: 0x1021, initialValue: 0x1D0F) + public static let buyPass = Self(polynomial: 0x8005) + public static let ccitt_false = Self(polynomial: 0x1021, initialValue: 0xFFFF) + public static let cdma2000 = Self(polynomial: 0xC867, initialValue: 0xFFFF) + public static let dds110 = Self(polynomial: 0x8005, initialValue: 0x800D) + public static let dectR = Self(polynomial: 0x0589, xorOut: 0x0001) + public static let dectX = Self(polynomial: 0x0589) + public static let dnp = Self(polynomial: 0x3D65, refIn: true, refOut: true, xorOut: 0xFFFF) + public static let en13757 = Self(polynomial: 0x3D65, xorOut: 0xFFFF) + public static let genibus = Self(polynomial: 0x1021, initialValue: 0xFFFF, xorOut: 0xFFFF) + public static let kermit = Self(polynomial: 0x1021, refIn: true, refOut: true) + public static let maxim = Self(polynomial: 0x8005, refIn: true, refOut: true, xorOut: 0xFFFF) + public static let mcrf4xx = Self(polynomial: 0x1021, initialValue: 0xFFFF, refIn: true, refOut: true) + public static let modbus = Self(polynomial: 0x8005, initialValue: 0xFFFF, refIn: true, refOut: true) + public static let riello = Self(polynomial: 0x1021, initialValue: 0xB2AA, refIn: true, refOut: true) + public static let t10_dif = Self(polynomial: 0x8BB7) + public static let teledisk = Self(polynomial: 0xA097) + public static let tms37157 = Self(polynomial: 0x1021, initialValue: 0x89EC, refIn: true, refOut: true) + public static let usb = Self(polynomial: 0x8005, initialValue: 0xFFFF, refIn: true, refOut: true, xorOut: 0xFFFF) + public static let x25 = Self(polynomial: 0x1021, initialValue: 0xFFFF, refIn: true, refOut: true, xorOut: 0xFFFF) + public static let xmodem = Self(polynomial: 0x1021) + +} diff --git a/Sources/CRC32.swift b/Sources/CRC32.swift new file mode 100644 index 0000000..7a52203 --- /dev/null +++ b/Sources/CRC32.swift @@ -0,0 +1,25 @@ +// +// CRC32.swift +// +// Copyright © 2020 QuickBird Studios. All rights reserved. +// + +import Foundation + +public typealias CRC32 = CRC + +extension CRC32 { + + public static let `default` = Self(polynomial: 0x04C11DB7, initialValue: 0xFFFFFFFF, refIn: true, refOut: true, xorOut: 0xFFFFFFFF) + public static let bzip2 = Self(polynomial: 0x04C11DB7, initialValue: 0xFFFFFFFF, xorOut: 0xFFFFFFFF) + public static let jamCRC = Self(polynomial: 0x04C11DB7, initialValue: 0xFFFFFFFF, refIn: true, refOut: true) + public static let mpeg2 = Self(polynomial: 0x04C11DB7, initialValue: 0xFFFFFFFF) + public static let posix = Self(polynomial: 0x04C11DB7, xorOut: 0xFFFFFFFF) + public static let sata = Self(polynomial: 0x04C11DB7, initialValue: 0x52325032) + public static let xfer = Self(polynomial: 0x000000AF) + + public static let c = Self(polynomial: 0x1EDC6F41, initialValue: 0xFFFFFFFF, refIn: true, refOut: true, xorOut: 0xFFFFFFFF) + public static let d = Self(polynomial: 0xA833982B, initialValue: 0xFFFFFFFF, refIn: true, refOut: true, xorOut: 0xFFFFFFFF) + public static let q = Self(polynomial: 0x814141AB) + +} diff --git a/Sources/CRC64.swift b/Sources/CRC64.swift new file mode 100644 index 0000000..a6d3a8d --- /dev/null +++ b/Sources/CRC64.swift @@ -0,0 +1,16 @@ +// +// CRC64.swift +// +// Copyright © 2020 QuickBird Studios. All rights reserved. +// + +import Foundation + +public typealias CRC64 = CRC + +extension CRC64 { + + public static let ecma = Self(polynomial: 0x42F0E1EBA9EA3693, initialValue: 0xFFFFFFFFFFFFFFFF, refIn: true, refOut: true, xorOut: 0xFFFFFFFFFFFFFFFF) + public static let iso = Self(polynomial: 0x000000000000001B, initialValue: 0xFFFFFFFFFFFFFFFF, refIn: true, refOut: true, xorOut: 0xFFFFFFFFFFFFFFFF) + +} diff --git a/Sources/CRC8.swift b/Sources/CRC8.swift new file mode 100644 index 0000000..ffb7a85 --- /dev/null +++ b/Sources/CRC8.swift @@ -0,0 +1,24 @@ +// +// CRC8.swift +// +// Copyright © 2020 QuickBird Studios. All rights reserved. +// + +import Foundation + +public typealias CRC8 = CRC + +extension CRC8 { + + public static let `default` = Self(polynomial: 0x07) + public static let cdma2000 = Self(polynomial: 0x9B, initialValue: 0xFF) + public static let darc = Self(polynomial: 0x39, refIn: true, refOut: true) + public static let dvbS2 = Self(polynomial: 0xD5) + public static let ebu = Self(polynomial: 0x1D, initialValue: 0xFF, refIn: true, refOut: true) + public static let iCode = Self(polynomial: 0x1D, initialValue: 0xFD) + public static let itu = Self(polynomial: 0x07, xorOut: 0x55) + public static let maxim = Self(polynomial: 0x31, refIn: true, refOut: true) + public static let rohc = Self(polynomial: 0x07, initialValue: 0xFF, refIn: true, refOut: true) + public static let wcdma = Self(polynomial: 0x9B, refIn: true, refOut: true) + +} diff --git a/Sources/CRCCalculator.swift b/Sources/CRCCalculator.swift new file mode 100644 index 0000000..887fb2c --- /dev/null +++ b/Sources/CRCCalculator.swift @@ -0,0 +1,73 @@ +// +// File.swift +// +// +// Created by Paul Kraft on 20.07.23. +// + +import Foundation + +public typealias CRC8Calculator = CRCCalculator +public typealias CRC16Calculator = CRCCalculator +public typealias CRC32Calculator = CRCCalculator +public typealias CRC64Calculator = CRCCalculator + +public struct CRCCalculator { + + // MARK: Stored Properties + + public private(set) var crc: CRC + public private(set) var currentValue: Value + + // MARK: Computed Properties + + public var finalValue: Value { + var finalValue = currentValue + crc.complete(&finalValue) + return finalValue + } + + // MARK: Initialization + + public init(_ crc: CRC) { + self.crc = crc + self.currentValue = crc.initialValue + } + + // MARK: Methods + + public mutating func append>(_ bytes: S) { + crc.calculate(for: bytes, in: ¤tValue) + } + + public mutating func reset(switchingTo newCRC: CRC? = nil) { + if let newCRC { crc = newCRC } + currentValue = crc.initialValue + } + +} + +extension CRCCalculator { + + public mutating func append(_ bytes: UInt8...) { + append(bytes) + } + + public mutating func append(bigEndian value: T) { + withUnsafeBytes(of: value.bigEndian) { append($0) } + } + + @available(macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0, *) + public mutating func append(bigEndian value: Float16) { + append(bigEndian: value.bitPattern) + } + + public mutating func append(bigEndian value: Float32) { + append(bigEndian: value.bitPattern) + } + + public mutating func append(bigEndian value: Float64) { + append(bigEndian: value.bitPattern) + } + +} diff --git a/Tests/CRC16Tests.swift b/Tests/CRC16Tests.swift new file mode 100644 index 0000000..5f9736b --- /dev/null +++ b/Tests/CRC16Tests.swift @@ -0,0 +1,950 @@ +// +// CRC16Tests.swift +// +// Copyright © 2020 QuickBird Studios. All rights reserved. +// + +import Foundation + +/// Source: https://crccalc.com +final class CRC16Tests: CRCTestCase { + + func testCalculatorASCII123456789() { + verifyCalculator( + for: "123456789".data(using: .ascii)!, + with: [ + .arc, + .aug_ccitt, + .buyPass, + .ccitt_false, + .cdma2000, + .dds110, + .dectR, + .dectX, + .dnp, + .en13757, + .genibus, + .kermit, + .maxim, + .mcrf4xx, + .modbus, + .riello, + .t10_dif, + .teledisk, + .tms37157, + .usb, + .x25, + .xmodem, + .a, + ] + ) + } + + func testASCII123456789() { + verify(for: "123456789".data(using: .ascii)!, expected: [ + (0xBB3D, .arc), + (0xE5CC, .aug_ccitt), + (0xFEE8, .buyPass), + (0x29B1, .ccitt_false), + (0x4C06, .cdma2000), + (0x9ECF, .dds110), + (0x007E, .dectR), + (0x007F, .dectX), + (0xEA82, .dnp), + (0xC2B7, .en13757), + (0xD64E, .genibus), + (0x2189, .kermit), + (0x44C2, .maxim), + (0x6F91, .mcrf4xx), + (0x4B37, .modbus), + (0x63D0, .riello), + (0xD0DB, .t10_dif), + (0x0FB3, .teledisk), + (0x26B1, .tms37157), + (0xB4C8, .usb), + (0x906E, .x25), + (0x31C3, .xmodem), + (0xBF05, .a), + ]) + } + + func test0x0204() { + verify(for: Data([0x02, 0x04]), expected: [ + (0xA300, .arc), + (0xA226, .aug_ccitt), + (0x0C18, .buyPass), + (0x3BE9, .ccitt_false), + (0x8AD8, .cdma2000), + (0x0C3C, .dds110), + (0x26F6, .dectR), + (0x26F7, .dectX), + (0x3D62, .dnp), + (0xDEBE, .en13757), + (0xC416, .genibus), + (0x7594, .kermit), + (0x5CFF, .maxim), + (0x852C, .mcrf4xx), + (0x1301, .modbus), + (0x86A2, .riello), + (0x58C1, .t10_dif), + (0x40F7, .teledisk), + (0x302D, .tms37157), + (0xECFE, .usb), + (0x7AD3, .x25), + (0x26E6, .xmodem), + (0x6B34, .a), + ]) + } + + func testLookupTableARC() throws { + verifyLookupTable(for: .arc, equalsTo: [ + 0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241, + 0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440, + 0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40, + 0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841, + 0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40, + 0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41, + 0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641, + 0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040, + 0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240, + 0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441, + 0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41, + 0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840, + 0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41, + 0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40, + 0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640, + 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041, + 0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240, + 0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441, + 0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41, + 0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840, + 0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41, + 0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40, + 0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640, + 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041, + 0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241, + 0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440, + 0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40, + 0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841, + 0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40, + 0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41, + 0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641, + 0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040, + ]) + } + + func testLookupTableAUG_CCITT() { + verifyLookupTable(for: .aug_ccitt, equalsTo: [ + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0, + ]) + } + + func testLookupTableBUYPASS() { + verifyLookupTable(for: .buyPass, equalsTo: [ + 0x0000, 0x8005, 0x800f, 0x000a, 0x801b, 0x001e, 0x0014, 0x8011, + 0x8033, 0x0036, 0x003c, 0x8039, 0x0028, 0x802d, 0x8027, 0x0022, + 0x8063, 0x0066, 0x006c, 0x8069, 0x0078, 0x807d, 0x8077, 0x0072, + 0x0050, 0x8055, 0x805f, 0x005a, 0x804b, 0x004e, 0x0044, 0x8041, + 0x80c3, 0x00c6, 0x00cc, 0x80c9, 0x00d8, 0x80dd, 0x80d7, 0x00d2, + 0x00f0, 0x80f5, 0x80ff, 0x00fa, 0x80eb, 0x00ee, 0x00e4, 0x80e1, + 0x00a0, 0x80a5, 0x80af, 0x00aa, 0x80bb, 0x00be, 0x00b4, 0x80b1, + 0x8093, 0x0096, 0x009c, 0x8099, 0x0088, 0x808d, 0x8087, 0x0082, + 0x8183, 0x0186, 0x018c, 0x8189, 0x0198, 0x819d, 0x8197, 0x0192, + 0x01b0, 0x81b5, 0x81bf, 0x01ba, 0x81ab, 0x01ae, 0x01a4, 0x81a1, + 0x01e0, 0x81e5, 0x81ef, 0x01ea, 0x81fb, 0x01fe, 0x01f4, 0x81f1, + 0x81d3, 0x01d6, 0x01dc, 0x81d9, 0x01c8, 0x81cd, 0x81c7, 0x01c2, + 0x0140, 0x8145, 0x814f, 0x014a, 0x815b, 0x015e, 0x0154, 0x8151, + 0x8173, 0x0176, 0x017c, 0x8179, 0x0168, 0x816d, 0x8167, 0x0162, + 0x8123, 0x0126, 0x012c, 0x8129, 0x0138, 0x813d, 0x8137, 0x0132, + 0x0110, 0x8115, 0x811f, 0x011a, 0x810b, 0x010e, 0x0104, 0x8101, + 0x8303, 0x0306, 0x030c, 0x8309, 0x0318, 0x831d, 0x8317, 0x0312, + 0x0330, 0x8335, 0x833f, 0x033a, 0x832b, 0x032e, 0x0324, 0x8321, + 0x0360, 0x8365, 0x836f, 0x036a, 0x837b, 0x037e, 0x0374, 0x8371, + 0x8353, 0x0356, 0x035c, 0x8359, 0x0348, 0x834d, 0x8347, 0x0342, + 0x03c0, 0x83c5, 0x83cf, 0x03ca, 0x83db, 0x03de, 0x03d4, 0x83d1, + 0x83f3, 0x03f6, 0x03fc, 0x83f9, 0x03e8, 0x83ed, 0x83e7, 0x03e2, + 0x83a3, 0x03a6, 0x03ac, 0x83a9, 0x03b8, 0x83bd, 0x83b7, 0x03b2, + 0x0390, 0x8395, 0x839f, 0x039a, 0x838b, 0x038e, 0x0384, 0x8381, + 0x0280, 0x8285, 0x828f, 0x028a, 0x829b, 0x029e, 0x0294, 0x8291, + 0x82b3, 0x02b6, 0x02bc, 0x82b9, 0x02a8, 0x82ad, 0x82a7, 0x02a2, + 0x82e3, 0x02e6, 0x02ec, 0x82e9, 0x02f8, 0x82fd, 0x82f7, 0x02f2, + 0x02d0, 0x82d5, 0x82df, 0x02da, 0x82cb, 0x02ce, 0x02c4, 0x82c1, + 0x8243, 0x0246, 0x024c, 0x8249, 0x0258, 0x825d, 0x8257, 0x0252, + 0x0270, 0x8275, 0x827f, 0x027a, 0x826b, 0x026e, 0x0264, 0x8261, + 0x0220, 0x8225, 0x822f, 0x022a, 0x823b, 0x023e, 0x0234, 0x8231, + 0x8213, 0x0216, 0x021c, 0x8219, 0x0208, 0x820d, 0x8207, 0x0202, + ]) + } + + func testLookupTableCCITT_FALSE() { + verifyLookupTable(for: .ccitt_false, equalsTo: [ + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0, + ]) + } + + func testLookupTableCDMA2000() { + verifyLookupTable(for: .cdma2000, equalsTo: [ + 0x0000, 0xc867, 0x58a9, 0x90ce, 0xb152, 0x7935, 0xe9fb, 0x219c, + 0xaac3, 0x62a4, 0xf26a, 0x3a0d, 0x1b91, 0xd3f6, 0x4338, 0x8b5f, + 0x9de1, 0x5586, 0xc548, 0x0d2f, 0x2cb3, 0xe4d4, 0x741a, 0xbc7d, + 0x3722, 0xff45, 0x6f8b, 0xa7ec, 0x8670, 0x4e17, 0xded9, 0x16be, + 0xf3a5, 0x3bc2, 0xab0c, 0x636b, 0x42f7, 0x8a90, 0x1a5e, 0xd239, + 0x5966, 0x9101, 0x01cf, 0xc9a8, 0xe834, 0x2053, 0xb09d, 0x78fa, + 0x6e44, 0xa623, 0x36ed, 0xfe8a, 0xdf16, 0x1771, 0x87bf, 0x4fd8, + 0xc487, 0x0ce0, 0x9c2e, 0x5449, 0x75d5, 0xbdb2, 0x2d7c, 0xe51b, + 0x2f2d, 0xe74a, 0x7784, 0xbfe3, 0x9e7f, 0x5618, 0xc6d6, 0x0eb1, + 0x85ee, 0x4d89, 0xdd47, 0x1520, 0x34bc, 0xfcdb, 0x6c15, 0xa472, + 0xb2cc, 0x7aab, 0xea65, 0x2202, 0x039e, 0xcbf9, 0x5b37, 0x9350, + 0x180f, 0xd068, 0x40a6, 0x88c1, 0xa95d, 0x613a, 0xf1f4, 0x3993, + 0xdc88, 0x14ef, 0x8421, 0x4c46, 0x6dda, 0xa5bd, 0x3573, 0xfd14, + 0x764b, 0xbe2c, 0x2ee2, 0xe685, 0xc719, 0x0f7e, 0x9fb0, 0x57d7, + 0x4169, 0x890e, 0x19c0, 0xd1a7, 0xf03b, 0x385c, 0xa892, 0x60f5, + 0xebaa, 0x23cd, 0xb303, 0x7b64, 0x5af8, 0x929f, 0x0251, 0xca36, + 0x5e5a, 0x963d, 0x06f3, 0xce94, 0xef08, 0x276f, 0xb7a1, 0x7fc6, + 0xf499, 0x3cfe, 0xac30, 0x6457, 0x45cb, 0x8dac, 0x1d62, 0xd505, + 0xc3bb, 0x0bdc, 0x9b12, 0x5375, 0x72e9, 0xba8e, 0x2a40, 0xe227, + 0x6978, 0xa11f, 0x31d1, 0xf9b6, 0xd82a, 0x104d, 0x8083, 0x48e4, + 0xadff, 0x6598, 0xf556, 0x3d31, 0x1cad, 0xd4ca, 0x4404, 0x8c63, + 0x073c, 0xcf5b, 0x5f95, 0x97f2, 0xb66e, 0x7e09, 0xeec7, 0x26a0, + 0x301e, 0xf879, 0x68b7, 0xa0d0, 0x814c, 0x492b, 0xd9e5, 0x1182, + 0x9add, 0x52ba, 0xc274, 0x0a13, 0x2b8f, 0xe3e8, 0x7326, 0xbb41, + 0x7177, 0xb910, 0x29de, 0xe1b9, 0xc025, 0x0842, 0x988c, 0x50eb, + 0xdbb4, 0x13d3, 0x831d, 0x4b7a, 0x6ae6, 0xa281, 0x324f, 0xfa28, + 0xec96, 0x24f1, 0xb43f, 0x7c58, 0x5dc4, 0x95a3, 0x056d, 0xcd0a, + 0x4655, 0x8e32, 0x1efc, 0xd69b, 0xf707, 0x3f60, 0xafae, 0x67c9, + 0x82d2, 0x4ab5, 0xda7b, 0x121c, 0x3380, 0xfbe7, 0x6b29, 0xa34e, + 0x2811, 0xe076, 0x70b8, 0xb8df, 0x9943, 0x5124, 0xc1ea, 0x098d, + 0x1f33, 0xd754, 0x479a, 0x8ffd, 0xae61, 0x6606, 0xf6c8, 0x3eaf, + 0xb5f0, 0x7d97, 0xed59, 0x253e, 0x04a2, 0xccc5, 0x5c0b, 0x946c, + ]) + } + + func testLookupTableDDS110() { + verifyLookupTable(for: .dds110, equalsTo: [ + 0x0000, 0x8005, 0x800f, 0x000a, 0x801b, 0x001e, 0x0014, 0x8011, + 0x8033, 0x0036, 0x003c, 0x8039, 0x0028, 0x802d, 0x8027, 0x0022, + 0x8063, 0x0066, 0x006c, 0x8069, 0x0078, 0x807d, 0x8077, 0x0072, + 0x0050, 0x8055, 0x805f, 0x005a, 0x804b, 0x004e, 0x0044, 0x8041, + 0x80c3, 0x00c6, 0x00cc, 0x80c9, 0x00d8, 0x80dd, 0x80d7, 0x00d2, + 0x00f0, 0x80f5, 0x80ff, 0x00fa, 0x80eb, 0x00ee, 0x00e4, 0x80e1, + 0x00a0, 0x80a5, 0x80af, 0x00aa, 0x80bb, 0x00be, 0x00b4, 0x80b1, + 0x8093, 0x0096, 0x009c, 0x8099, 0x0088, 0x808d, 0x8087, 0x0082, + 0x8183, 0x0186, 0x018c, 0x8189, 0x0198, 0x819d, 0x8197, 0x0192, + 0x01b0, 0x81b5, 0x81bf, 0x01ba, 0x81ab, 0x01ae, 0x01a4, 0x81a1, + 0x01e0, 0x81e5, 0x81ef, 0x01ea, 0x81fb, 0x01fe, 0x01f4, 0x81f1, + 0x81d3, 0x01d6, 0x01dc, 0x81d9, 0x01c8, 0x81cd, 0x81c7, 0x01c2, + 0x0140, 0x8145, 0x814f, 0x014a, 0x815b, 0x015e, 0x0154, 0x8151, + 0x8173, 0x0176, 0x017c, 0x8179, 0x0168, 0x816d, 0x8167, 0x0162, + 0x8123, 0x0126, 0x012c, 0x8129, 0x0138, 0x813d, 0x8137, 0x0132, + 0x0110, 0x8115, 0x811f, 0x011a, 0x810b, 0x010e, 0x0104, 0x8101, + 0x8303, 0x0306, 0x030c, 0x8309, 0x0318, 0x831d, 0x8317, 0x0312, + 0x0330, 0x8335, 0x833f, 0x033a, 0x832b, 0x032e, 0x0324, 0x8321, + 0x0360, 0x8365, 0x836f, 0x036a, 0x837b, 0x037e, 0x0374, 0x8371, + 0x8353, 0x0356, 0x035c, 0x8359, 0x0348, 0x834d, 0x8347, 0x0342, + 0x03c0, 0x83c5, 0x83cf, 0x03ca, 0x83db, 0x03de, 0x03d4, 0x83d1, + 0x83f3, 0x03f6, 0x03fc, 0x83f9, 0x03e8, 0x83ed, 0x83e7, 0x03e2, + 0x83a3, 0x03a6, 0x03ac, 0x83a9, 0x03b8, 0x83bd, 0x83b7, 0x03b2, + 0x0390, 0x8395, 0x839f, 0x039a, 0x838b, 0x038e, 0x0384, 0x8381, + 0x0280, 0x8285, 0x828f, 0x028a, 0x829b, 0x029e, 0x0294, 0x8291, + 0x82b3, 0x02b6, 0x02bc, 0x82b9, 0x02a8, 0x82ad, 0x82a7, 0x02a2, + 0x82e3, 0x02e6, 0x02ec, 0x82e9, 0x02f8, 0x82fd, 0x82f7, 0x02f2, + 0x02d0, 0x82d5, 0x82df, 0x02da, 0x82cb, 0x02ce, 0x02c4, 0x82c1, + 0x8243, 0x0246, 0x024c, 0x8249, 0x0258, 0x825d, 0x8257, 0x0252, + 0x0270, 0x8275, 0x827f, 0x027a, 0x826b, 0x026e, 0x0264, 0x8261, + 0x0220, 0x8225, 0x822f, 0x022a, 0x823b, 0x023e, 0x0234, 0x8231, + 0x8213, 0x0216, 0x021c, 0x8219, 0x0208, 0x820d, 0x8207, 0x0202, + ]) + } + + func testLookupTableDECTR() { + verifyLookupTable(for: .dectR, equalsTo: [ + 0x0000, 0x0589, 0x0b12, 0x0e9b, 0x1624, 0x13ad, 0x1d36, 0x18bf, + 0x2c48, 0x29c1, 0x275a, 0x22d3, 0x3a6c, 0x3fe5, 0x317e, 0x34f7, + 0x5890, 0x5d19, 0x5382, 0x560b, 0x4eb4, 0x4b3d, 0x45a6, 0x402f, + 0x74d8, 0x7151, 0x7fca, 0x7a43, 0x62fc, 0x6775, 0x69ee, 0x6c67, + 0xb120, 0xb4a9, 0xba32, 0xbfbb, 0xa704, 0xa28d, 0xac16, 0xa99f, + 0x9d68, 0x98e1, 0x967a, 0x93f3, 0x8b4c, 0x8ec5, 0x805e, 0x85d7, + 0xe9b0, 0xec39, 0xe2a2, 0xe72b, 0xff94, 0xfa1d, 0xf486, 0xf10f, + 0xc5f8, 0xc071, 0xceea, 0xcb63, 0xd3dc, 0xd655, 0xd8ce, 0xdd47, + 0x67c9, 0x6240, 0x6cdb, 0x6952, 0x71ed, 0x7464, 0x7aff, 0x7f76, + 0x4b81, 0x4e08, 0x4093, 0x451a, 0x5da5, 0x582c, 0x56b7, 0x533e, + 0x3f59, 0x3ad0, 0x344b, 0x31c2, 0x297d, 0x2cf4, 0x226f, 0x27e6, + 0x1311, 0x1698, 0x1803, 0x1d8a, 0x0535, 0x00bc, 0x0e27, 0x0bae, + 0xd6e9, 0xd360, 0xddfb, 0xd872, 0xc0cd, 0xc544, 0xcbdf, 0xce56, + 0xfaa1, 0xff28, 0xf1b3, 0xf43a, 0xec85, 0xe90c, 0xe797, 0xe21e, + 0x8e79, 0x8bf0, 0x856b, 0x80e2, 0x985d, 0x9dd4, 0x934f, 0x96c6, + 0xa231, 0xa7b8, 0xa923, 0xacaa, 0xb415, 0xb19c, 0xbf07, 0xba8e, + 0xcf92, 0xca1b, 0xc480, 0xc109, 0xd9b6, 0xdc3f, 0xd2a4, 0xd72d, + 0xe3da, 0xe653, 0xe8c8, 0xed41, 0xf5fe, 0xf077, 0xfeec, 0xfb65, + 0x9702, 0x928b, 0x9c10, 0x9999, 0x8126, 0x84af, 0x8a34, 0x8fbd, + 0xbb4a, 0xbec3, 0xb058, 0xb5d1, 0xad6e, 0xa8e7, 0xa67c, 0xa3f5, + 0x7eb2, 0x7b3b, 0x75a0, 0x7029, 0x6896, 0x6d1f, 0x6384, 0x660d, + 0x52fa, 0x5773, 0x59e8, 0x5c61, 0x44de, 0x4157, 0x4fcc, 0x4a45, + 0x2622, 0x23ab, 0x2d30, 0x28b9, 0x3006, 0x358f, 0x3b14, 0x3e9d, + 0x0a6a, 0x0fe3, 0x0178, 0x04f1, 0x1c4e, 0x19c7, 0x175c, 0x12d5, + 0xa85b, 0xadd2, 0xa349, 0xa6c0, 0xbe7f, 0xbbf6, 0xb56d, 0xb0e4, + 0x8413, 0x819a, 0x8f01, 0x8a88, 0x9237, 0x97be, 0x9925, 0x9cac, + 0xf0cb, 0xf542, 0xfbd9, 0xfe50, 0xe6ef, 0xe366, 0xedfd, 0xe874, + 0xdc83, 0xd90a, 0xd791, 0xd218, 0xcaa7, 0xcf2e, 0xc1b5, 0xc43c, + 0x197b, 0x1cf2, 0x1269, 0x17e0, 0x0f5f, 0x0ad6, 0x044d, 0x01c4, + 0x3533, 0x30ba, 0x3e21, 0x3ba8, 0x2317, 0x269e, 0x2805, 0x2d8c, + 0x41eb, 0x4462, 0x4af9, 0x4f70, 0x57cf, 0x5246, 0x5cdd, 0x5954, + 0x6da3, 0x682a, 0x66b1, 0x6338, 0x7b87, 0x7e0e, 0x7095, 0x751c, + ]) + } + + func testLookupTableDECTX() { + verifyLookupTable(for: .dectX, equalsTo: [ + 0x0000, 0x0589, 0x0b12, 0x0e9b, 0x1624, 0x13ad, 0x1d36, 0x18bf, + 0x2c48, 0x29c1, 0x275a, 0x22d3, 0x3a6c, 0x3fe5, 0x317e, 0x34f7, + 0x5890, 0x5d19, 0x5382, 0x560b, 0x4eb4, 0x4b3d, 0x45a6, 0x402f, + 0x74d8, 0x7151, 0x7fca, 0x7a43, 0x62fc, 0x6775, 0x69ee, 0x6c67, + 0xb120, 0xb4a9, 0xba32, 0xbfbb, 0xa704, 0xa28d, 0xac16, 0xa99f, + 0x9d68, 0x98e1, 0x967a, 0x93f3, 0x8b4c, 0x8ec5, 0x805e, 0x85d7, + 0xe9b0, 0xec39, 0xe2a2, 0xe72b, 0xff94, 0xfa1d, 0xf486, 0xf10f, + 0xc5f8, 0xc071, 0xceea, 0xcb63, 0xd3dc, 0xd655, 0xd8ce, 0xdd47, + 0x67c9, 0x6240, 0x6cdb, 0x6952, 0x71ed, 0x7464, 0x7aff, 0x7f76, + 0x4b81, 0x4e08, 0x4093, 0x451a, 0x5da5, 0x582c, 0x56b7, 0x533e, + 0x3f59, 0x3ad0, 0x344b, 0x31c2, 0x297d, 0x2cf4, 0x226f, 0x27e6, + 0x1311, 0x1698, 0x1803, 0x1d8a, 0x0535, 0x00bc, 0x0e27, 0x0bae, + 0xd6e9, 0xd360, 0xddfb, 0xd872, 0xc0cd, 0xc544, 0xcbdf, 0xce56, + 0xfaa1, 0xff28, 0xf1b3, 0xf43a, 0xec85, 0xe90c, 0xe797, 0xe21e, + 0x8e79, 0x8bf0, 0x856b, 0x80e2, 0x985d, 0x9dd4, 0x934f, 0x96c6, + 0xa231, 0xa7b8, 0xa923, 0xacaa, 0xb415, 0xb19c, 0xbf07, 0xba8e, + 0xcf92, 0xca1b, 0xc480, 0xc109, 0xd9b6, 0xdc3f, 0xd2a4, 0xd72d, + 0xe3da, 0xe653, 0xe8c8, 0xed41, 0xf5fe, 0xf077, 0xfeec, 0xfb65, + 0x9702, 0x928b, 0x9c10, 0x9999, 0x8126, 0x84af, 0x8a34, 0x8fbd, + 0xbb4a, 0xbec3, 0xb058, 0xb5d1, 0xad6e, 0xa8e7, 0xa67c, 0xa3f5, + 0x7eb2, 0x7b3b, 0x75a0, 0x7029, 0x6896, 0x6d1f, 0x6384, 0x660d, + 0x52fa, 0x5773, 0x59e8, 0x5c61, 0x44de, 0x4157, 0x4fcc, 0x4a45, + 0x2622, 0x23ab, 0x2d30, 0x28b9, 0x3006, 0x358f, 0x3b14, 0x3e9d, + 0x0a6a, 0x0fe3, 0x0178, 0x04f1, 0x1c4e, 0x19c7, 0x175c, 0x12d5, + 0xa85b, 0xadd2, 0xa349, 0xa6c0, 0xbe7f, 0xbbf6, 0xb56d, 0xb0e4, + 0x8413, 0x819a, 0x8f01, 0x8a88, 0x9237, 0x97be, 0x9925, 0x9cac, + 0xf0cb, 0xf542, 0xfbd9, 0xfe50, 0xe6ef, 0xe366, 0xedfd, 0xe874, + 0xdc83, 0xd90a, 0xd791, 0xd218, 0xcaa7, 0xcf2e, 0xc1b5, 0xc43c, + 0x197b, 0x1cf2, 0x1269, 0x17e0, 0x0f5f, 0x0ad6, 0x044d, 0x01c4, + 0x3533, 0x30ba, 0x3e21, 0x3ba8, 0x2317, 0x269e, 0x2805, 0x2d8c, + 0x41eb, 0x4462, 0x4af9, 0x4f70, 0x57cf, 0x5246, 0x5cdd, 0x5954, + 0x6da3, 0x682a, 0x66b1, 0x6338, 0x7b87, 0x7e0e, 0x7095, 0x751c, + ]) + } + + func testLookupTableDNP() { + verifyLookupTable(for: .dnp, equalsTo: [ + 0x0000, 0x365e, 0x6cbc, 0x5ae2, 0xd978, 0xef26, 0xb5c4, 0x839a, + 0xff89, 0xc9d7, 0x9335, 0xa56b, 0x26f1, 0x10af, 0x4a4d, 0x7c13, + 0xb26b, 0x8435, 0xded7, 0xe889, 0x6b13, 0x5d4d, 0x07af, 0x31f1, + 0x4de2, 0x7bbc, 0x215e, 0x1700, 0x949a, 0xa2c4, 0xf826, 0xce78, + 0x29af, 0x1ff1, 0x4513, 0x734d, 0xf0d7, 0xc689, 0x9c6b, 0xaa35, + 0xd626, 0xe078, 0xba9a, 0x8cc4, 0x0f5e, 0x3900, 0x63e2, 0x55bc, + 0x9bc4, 0xad9a, 0xf778, 0xc126, 0x42bc, 0x74e2, 0x2e00, 0x185e, + 0x644d, 0x5213, 0x08f1, 0x3eaf, 0xbd35, 0x8b6b, 0xd189, 0xe7d7, + 0x535e, 0x6500, 0x3fe2, 0x09bc, 0x8a26, 0xbc78, 0xe69a, 0xd0c4, + 0xacd7, 0x9a89, 0xc06b, 0xf635, 0x75af, 0x43f1, 0x1913, 0x2f4d, + 0xe135, 0xd76b, 0x8d89, 0xbbd7, 0x384d, 0x0e13, 0x54f1, 0x62af, + 0x1ebc, 0x28e2, 0x7200, 0x445e, 0xc7c4, 0xf19a, 0xab78, 0x9d26, + 0x7af1, 0x4caf, 0x164d, 0x2013, 0xa389, 0x95d7, 0xcf35, 0xf96b, + 0x8578, 0xb326, 0xe9c4, 0xdf9a, 0x5c00, 0x6a5e, 0x30bc, 0x06e2, + 0xc89a, 0xfec4, 0xa426, 0x9278, 0x11e2, 0x27bc, 0x7d5e, 0x4b00, + 0x3713, 0x014d, 0x5baf, 0x6df1, 0xee6b, 0xd835, 0x82d7, 0xb489, + 0xa6bc, 0x90e2, 0xca00, 0xfc5e, 0x7fc4, 0x499a, 0x1378, 0x2526, + 0x5935, 0x6f6b, 0x3589, 0x03d7, 0x804d, 0xb613, 0xecf1, 0xdaaf, + 0x14d7, 0x2289, 0x786b, 0x4e35, 0xcdaf, 0xfbf1, 0xa113, 0x974d, + 0xeb5e, 0xdd00, 0x87e2, 0xb1bc, 0x3226, 0x0478, 0x5e9a, 0x68c4, + 0x8f13, 0xb94d, 0xe3af, 0xd5f1, 0x566b, 0x6035, 0x3ad7, 0x0c89, + 0x709a, 0x46c4, 0x1c26, 0x2a78, 0xa9e2, 0x9fbc, 0xc55e, 0xf300, + 0x3d78, 0x0b26, 0x51c4, 0x679a, 0xe400, 0xd25e, 0x88bc, 0xbee2, + 0xc2f1, 0xf4af, 0xae4d, 0x9813, 0x1b89, 0x2dd7, 0x7735, 0x416b, + 0xf5e2, 0xc3bc, 0x995e, 0xaf00, 0x2c9a, 0x1ac4, 0x4026, 0x7678, + 0x0a6b, 0x3c35, 0x66d7, 0x5089, 0xd313, 0xe54d, 0xbfaf, 0x89f1, + 0x4789, 0x71d7, 0x2b35, 0x1d6b, 0x9ef1, 0xa8af, 0xf24d, 0xc413, + 0xb800, 0x8e5e, 0xd4bc, 0xe2e2, 0x6178, 0x5726, 0x0dc4, 0x3b9a, + 0xdc4d, 0xea13, 0xb0f1, 0x86af, 0x0535, 0x336b, 0x6989, 0x5fd7, + 0x23c4, 0x159a, 0x4f78, 0x7926, 0xfabc, 0xcce2, 0x9600, 0xa05e, + 0x6e26, 0x5878, 0x029a, 0x34c4, 0xb75e, 0x8100, 0xdbe2, 0xedbc, + 0x91af, 0xa7f1, 0xfd13, 0xcb4d, 0x48d7, 0x7e89, 0x246b, 0x1235, + ]) + } + + func testLookupTableEN13757() { + verifyLookupTable(for: .en13757, equalsTo: [ + 0x0000, 0x3d65, 0x7aca, 0x47af, 0xf594, 0xc8f1, 0x8f5e, 0xb23b, + 0xd64d, 0xeb28, 0xac87, 0x91e2, 0x23d9, 0x1ebc, 0x5913, 0x6476, + 0x91ff, 0xac9a, 0xeb35, 0xd650, 0x646b, 0x590e, 0x1ea1, 0x23c4, + 0x47b2, 0x7ad7, 0x3d78, 0x001d, 0xb226, 0x8f43, 0xc8ec, 0xf589, + 0x1e9b, 0x23fe, 0x6451, 0x5934, 0xeb0f, 0xd66a, 0x91c5, 0xaca0, + 0xc8d6, 0xf5b3, 0xb21c, 0x8f79, 0x3d42, 0x0027, 0x4788, 0x7aed, + 0x8f64, 0xb201, 0xf5ae, 0xc8cb, 0x7af0, 0x4795, 0x003a, 0x3d5f, + 0x5929, 0x644c, 0x23e3, 0x1e86, 0xacbd, 0x91d8, 0xd677, 0xeb12, + 0x3d36, 0x0053, 0x47fc, 0x7a99, 0xc8a2, 0xf5c7, 0xb268, 0x8f0d, + 0xeb7b, 0xd61e, 0x91b1, 0xacd4, 0x1eef, 0x238a, 0x6425, 0x5940, + 0xacc9, 0x91ac, 0xd603, 0xeb66, 0x595d, 0x6438, 0x2397, 0x1ef2, + 0x7a84, 0x47e1, 0x004e, 0x3d2b, 0x8f10, 0xb275, 0xf5da, 0xc8bf, + 0x23ad, 0x1ec8, 0x5967, 0x6402, 0xd639, 0xeb5c, 0xacf3, 0x9196, + 0xf5e0, 0xc885, 0x8f2a, 0xb24f, 0x0074, 0x3d11, 0x7abe, 0x47db, + 0xb252, 0x8f37, 0xc898, 0xf5fd, 0x47c6, 0x7aa3, 0x3d0c, 0x0069, + 0x641f, 0x597a, 0x1ed5, 0x23b0, 0x918b, 0xacee, 0xeb41, 0xd624, + 0x7a6c, 0x4709, 0x00a6, 0x3dc3, 0x8ff8, 0xb29d, 0xf532, 0xc857, + 0xac21, 0x9144, 0xd6eb, 0xeb8e, 0x59b5, 0x64d0, 0x237f, 0x1e1a, + 0xeb93, 0xd6f6, 0x9159, 0xac3c, 0x1e07, 0x2362, 0x64cd, 0x59a8, + 0x3dde, 0x00bb, 0x4714, 0x7a71, 0xc84a, 0xf52f, 0xb280, 0x8fe5, + 0x64f7, 0x5992, 0x1e3d, 0x2358, 0x9163, 0xac06, 0xeba9, 0xd6cc, + 0xb2ba, 0x8fdf, 0xc870, 0xf515, 0x472e, 0x7a4b, 0x3de4, 0x0081, + 0xf508, 0xc86d, 0x8fc2, 0xb2a7, 0x009c, 0x3df9, 0x7a56, 0x4733, + 0x2345, 0x1e20, 0x598f, 0x64ea, 0xd6d1, 0xebb4, 0xac1b, 0x917e, + 0x475a, 0x7a3f, 0x3d90, 0x00f5, 0xb2ce, 0x8fab, 0xc804, 0xf561, + 0x9117, 0xac72, 0xebdd, 0xd6b8, 0x6483, 0x59e6, 0x1e49, 0x232c, + 0xd6a5, 0xebc0, 0xac6f, 0x910a, 0x2331, 0x1e54, 0x59fb, 0x649e, + 0x00e8, 0x3d8d, 0x7a22, 0x4747, 0xf57c, 0xc819, 0x8fb6, 0xb2d3, + 0x59c1, 0x64a4, 0x230b, 0x1e6e, 0xac55, 0x9130, 0xd69f, 0xebfa, + 0x8f8c, 0xb2e9, 0xf546, 0xc823, 0x7a18, 0x477d, 0x00d2, 0x3db7, + 0xc83e, 0xf55b, 0xb2f4, 0x8f91, 0x3daa, 0x00cf, 0x4760, 0x7a05, + 0x1e73, 0x2316, 0x64b9, 0x59dc, 0xebe7, 0xd682, 0x912d, 0xac48, + ]) + } + + func testLookupTableGENIBUS() { + verifyLookupTable(for: .genibus, equalsTo: [ + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0, + ]) + } + + func testLookupTableKERMIT() { + verifyLookupTable(for: .kermit, equalsTo: [ + 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, + 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, + 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, + 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, + 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, + 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, + 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, + 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, + 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, + 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, + 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, + 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, + 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, + 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, + 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, + 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, + 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, + 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, + 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, + 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, + 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, + 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, + 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, + 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, + 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, + 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, + 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, + 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, + 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, + 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, + 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, + 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78, + ]) + } + + func testLookupTableMAXIM() { + verifyLookupTable(for: .maxim, equalsTo: [ + 0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241, + 0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440, + 0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40, + 0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841, + 0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40, + 0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41, + 0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641, + 0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040, + 0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240, + 0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441, + 0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41, + 0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840, + 0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41, + 0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40, + 0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640, + 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041, + 0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240, + 0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441, + 0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41, + 0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840, + 0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41, + 0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40, + 0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640, + 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041, + 0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241, + 0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440, + 0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40, + 0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841, + 0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40, + 0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41, + 0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641, + 0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040, + ]) + } + + func testLookupTableMCRF4XX() { + verifyLookupTable(for: .mcrf4xx, equalsTo: [ + 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, + 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, + 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, + 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, + 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, + 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, + 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, + 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, + 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, + 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, + 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, + 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, + 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, + 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, + 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, + 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, + 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, + 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, + 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, + 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, + 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, + 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, + 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, + 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, + 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, + 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, + 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, + 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, + 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, + 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, + 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, + 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78, + ]) + } + + func testLookupTableMODBUS() { + verifyLookupTable(for: .modbus, equalsTo: [ + 0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241, + 0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440, + 0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40, + 0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841, + 0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40, + 0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41, + 0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641, + 0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040, + 0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240, + 0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441, + 0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41, + 0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840, + 0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41, + 0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40, + 0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640, + 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041, + 0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240, + 0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441, + 0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41, + 0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840, + 0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41, + 0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40, + 0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640, + 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041, + 0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241, + 0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440, + 0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40, + 0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841, + 0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40, + 0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41, + 0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641, + 0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040, + ]) + } + + func testLookupTableRIELLO() { + verifyLookupTable(for: .riello, equalsTo: [ + 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, + 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, + 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, + 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, + 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, + 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, + 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, + 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, + 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, + 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, + 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, + 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, + 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, + 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, + 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, + 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, + 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, + 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, + 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, + 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, + 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, + 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, + 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, + 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, + 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, + 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, + 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, + 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, + 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, + 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, + 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, + 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78, + ]) + } + + func testLookupTableT10DIF() { + verifyLookupTable(for: .t10_dif, equalsTo: [ + 0x0000, 0x8bb7, 0x9cd9, 0x176e, 0xb205, 0x39b2, 0x2edc, 0xa56b, + 0xefbd, 0x640a, 0x7364, 0xf8d3, 0x5db8, 0xd60f, 0xc161, 0x4ad6, + 0x54cd, 0xdf7a, 0xc814, 0x43a3, 0xe6c8, 0x6d7f, 0x7a11, 0xf1a6, + 0xbb70, 0x30c7, 0x27a9, 0xac1e, 0x0975, 0x82c2, 0x95ac, 0x1e1b, + 0xa99a, 0x222d, 0x3543, 0xbef4, 0x1b9f, 0x9028, 0x8746, 0x0cf1, + 0x4627, 0xcd90, 0xdafe, 0x5149, 0xf422, 0x7f95, 0x68fb, 0xe34c, + 0xfd57, 0x76e0, 0x618e, 0xea39, 0x4f52, 0xc4e5, 0xd38b, 0x583c, + 0x12ea, 0x995d, 0x8e33, 0x0584, 0xa0ef, 0x2b58, 0x3c36, 0xb781, + 0xd883, 0x5334, 0x445a, 0xcfed, 0x6a86, 0xe131, 0xf65f, 0x7de8, + 0x373e, 0xbc89, 0xabe7, 0x2050, 0x853b, 0x0e8c, 0x19e2, 0x9255, + 0x8c4e, 0x07f9, 0x1097, 0x9b20, 0x3e4b, 0xb5fc, 0xa292, 0x2925, + 0x63f3, 0xe844, 0xff2a, 0x749d, 0xd1f6, 0x5a41, 0x4d2f, 0xc698, + 0x7119, 0xfaae, 0xedc0, 0x6677, 0xc31c, 0x48ab, 0x5fc5, 0xd472, + 0x9ea4, 0x1513, 0x027d, 0x89ca, 0x2ca1, 0xa716, 0xb078, 0x3bcf, + 0x25d4, 0xae63, 0xb90d, 0x32ba, 0x97d1, 0x1c66, 0x0b08, 0x80bf, + 0xca69, 0x41de, 0x56b0, 0xdd07, 0x786c, 0xf3db, 0xe4b5, 0x6f02, + 0x3ab1, 0xb106, 0xa668, 0x2ddf, 0x88b4, 0x0303, 0x146d, 0x9fda, + 0xd50c, 0x5ebb, 0x49d5, 0xc262, 0x6709, 0xecbe, 0xfbd0, 0x7067, + 0x6e7c, 0xe5cb, 0xf2a5, 0x7912, 0xdc79, 0x57ce, 0x40a0, 0xcb17, + 0x81c1, 0x0a76, 0x1d18, 0x96af, 0x33c4, 0xb873, 0xaf1d, 0x24aa, + 0x932b, 0x189c, 0x0ff2, 0x8445, 0x212e, 0xaa99, 0xbdf7, 0x3640, + 0x7c96, 0xf721, 0xe04f, 0x6bf8, 0xce93, 0x4524, 0x524a, 0xd9fd, + 0xc7e6, 0x4c51, 0x5b3f, 0xd088, 0x75e3, 0xfe54, 0xe93a, 0x628d, + 0x285b, 0xa3ec, 0xb482, 0x3f35, 0x9a5e, 0x11e9, 0x0687, 0x8d30, + 0xe232, 0x6985, 0x7eeb, 0xf55c, 0x5037, 0xdb80, 0xccee, 0x4759, + 0x0d8f, 0x8638, 0x9156, 0x1ae1, 0xbf8a, 0x343d, 0x2353, 0xa8e4, + 0xb6ff, 0x3d48, 0x2a26, 0xa191, 0x04fa, 0x8f4d, 0x9823, 0x1394, + 0x5942, 0xd2f5, 0xc59b, 0x4e2c, 0xeb47, 0x60f0, 0x779e, 0xfc29, + 0x4ba8, 0xc01f, 0xd771, 0x5cc6, 0xf9ad, 0x721a, 0x6574, 0xeec3, + 0xa415, 0x2fa2, 0x38cc, 0xb37b, 0x1610, 0x9da7, 0x8ac9, 0x017e, + 0x1f65, 0x94d2, 0x83bc, 0x080b, 0xad60, 0x26d7, 0x31b9, 0xba0e, + 0xf0d8, 0x7b6f, 0x6c01, 0xe7b6, 0x42dd, 0xc96a, 0xde04, 0x55b3, + ]) + } + + func testLookupTableTELEDISK() { + verifyLookupTable(for: .teledisk, equalsTo: [ + 0x0000, 0xa097, 0xe1b9, 0x412e, 0x63e5, 0xc372, 0x825c, 0x22cb, + 0xc7ca, 0x675d, 0x2673, 0x86e4, 0xa42f, 0x04b8, 0x4596, 0xe501, + 0x2f03, 0x8f94, 0xceba, 0x6e2d, 0x4ce6, 0xec71, 0xad5f, 0x0dc8, + 0xe8c9, 0x485e, 0x0970, 0xa9e7, 0x8b2c, 0x2bbb, 0x6a95, 0xca02, + 0x5e06, 0xfe91, 0xbfbf, 0x1f28, 0x3de3, 0x9d74, 0xdc5a, 0x7ccd, + 0x99cc, 0x395b, 0x7875, 0xd8e2, 0xfa29, 0x5abe, 0x1b90, 0xbb07, + 0x7105, 0xd192, 0x90bc, 0x302b, 0x12e0, 0xb277, 0xf359, 0x53ce, + 0xb6cf, 0x1658, 0x5776, 0xf7e1, 0xd52a, 0x75bd, 0x3493, 0x9404, + 0xbc0c, 0x1c9b, 0x5db5, 0xfd22, 0xdfe9, 0x7f7e, 0x3e50, 0x9ec7, + 0x7bc6, 0xdb51, 0x9a7f, 0x3ae8, 0x1823, 0xb8b4, 0xf99a, 0x590d, + 0x930f, 0x3398, 0x72b6, 0xd221, 0xf0ea, 0x507d, 0x1153, 0xb1c4, + 0x54c5, 0xf452, 0xb57c, 0x15eb, 0x3720, 0x97b7, 0xd699, 0x760e, + 0xe20a, 0x429d, 0x03b3, 0xa324, 0x81ef, 0x2178, 0x6056, 0xc0c1, + 0x25c0, 0x8557, 0xc479, 0x64ee, 0x4625, 0xe6b2, 0xa79c, 0x070b, + 0xcd09, 0x6d9e, 0x2cb0, 0x8c27, 0xaeec, 0x0e7b, 0x4f55, 0xefc2, + 0x0ac3, 0xaa54, 0xeb7a, 0x4bed, 0x6926, 0xc9b1, 0x889f, 0x2808, + 0xd88f, 0x7818, 0x3936, 0x99a1, 0xbb6a, 0x1bfd, 0x5ad3, 0xfa44, + 0x1f45, 0xbfd2, 0xfefc, 0x5e6b, 0x7ca0, 0xdc37, 0x9d19, 0x3d8e, + 0xf78c, 0x571b, 0x1635, 0xb6a2, 0x9469, 0x34fe, 0x75d0, 0xd547, + 0x3046, 0x90d1, 0xd1ff, 0x7168, 0x53a3, 0xf334, 0xb21a, 0x128d, + 0x8689, 0x261e, 0x6730, 0xc7a7, 0xe56c, 0x45fb, 0x04d5, 0xa442, + 0x4143, 0xe1d4, 0xa0fa, 0x006d, 0x22a6, 0x8231, 0xc31f, 0x6388, + 0xa98a, 0x091d, 0x4833, 0xe8a4, 0xca6f, 0x6af8, 0x2bd6, 0x8b41, + 0x6e40, 0xced7, 0x8ff9, 0x2f6e, 0x0da5, 0xad32, 0xec1c, 0x4c8b, + 0x6483, 0xc414, 0x853a, 0x25ad, 0x0766, 0xa7f1, 0xe6df, 0x4648, + 0xa349, 0x03de, 0x42f0, 0xe267, 0xc0ac, 0x603b, 0x2115, 0x8182, + 0x4b80, 0xeb17, 0xaa39, 0x0aae, 0x2865, 0x88f2, 0xc9dc, 0x694b, + 0x8c4a, 0x2cdd, 0x6df3, 0xcd64, 0xefaf, 0x4f38, 0x0e16, 0xae81, + 0x3a85, 0x9a12, 0xdb3c, 0x7bab, 0x5960, 0xf9f7, 0xb8d9, 0x184e, + 0xfd4f, 0x5dd8, 0x1cf6, 0xbc61, 0x9eaa, 0x3e3d, 0x7f13, 0xdf84, + 0x1586, 0xb511, 0xf43f, 0x54a8, 0x7663, 0xd6f4, 0x97da, 0x374d, + 0xd24c, 0x72db, 0x33f5, 0x9362, 0xb1a9, 0x113e, 0x5010, 0xf087, + ]) + } + + func testLookupTableTMS37157() { + verifyLookupTable(for: .tms37157, equalsTo: [ + 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, + 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, + 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, + 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, + 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, + 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, + 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, + 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, + 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, + 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, + 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, + 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, + 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, + 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, + 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, + 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, + 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, + 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, + 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, + 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, + 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, + 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, + 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, + 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, + 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, + 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, + 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, + 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, + 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, + 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, + 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, + 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78, + ]) + } + + func testLookupTableUSB() { + verifyLookupTable(for: .usb, equalsTo: [ + 0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241, + 0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440, + 0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40, + 0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841, + 0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40, + 0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41, + 0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641, + 0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040, + 0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240, + 0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441, + 0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41, + 0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840, + 0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41, + 0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40, + 0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640, + 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041, + 0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240, + 0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441, + 0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41, + 0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840, + 0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41, + 0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40, + 0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640, + 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041, + 0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241, + 0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440, + 0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40, + 0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841, + 0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40, + 0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41, + 0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641, + 0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040, + ]) + } + + func testLookupTableX25() { + verifyLookupTable(for: .x25, equalsTo: [ + 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, + 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, + 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, + 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, + 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, + 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, + 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, + 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, + 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, + 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, + 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, + 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, + 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, + 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, + 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, + 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, + 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, + 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, + 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, + 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, + 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, + 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, + 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, + 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, + 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, + 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, + 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, + 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, + 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, + 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, + 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, + 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78, + ]) + } + + func testLookupTableXMODEM() { + verifyLookupTable(for: .xmodem, equalsTo: [ + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0, + ]) + } + + func testLookupTableA() { + verifyLookupTable(for: .a, equalsTo: [ + 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, + 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, + 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, + 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, + 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, + 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, + 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, + 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, + 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, + 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, + 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, + 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, + 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, + 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, + 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, + 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, + 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, + 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, + 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, + 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, + 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, + 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, + 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, + 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, + 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, + 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, + 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, + 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, + 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, + 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, + 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, + 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78, + ]) + } + +} diff --git a/Tests/CRC32Tests.swift b/Tests/CRC32Tests.swift new file mode 100644 index 0000000..df0611e --- /dev/null +++ b/Tests/CRC32Tests.swift @@ -0,0 +1,427 @@ +// +// CRC32Tests.swift +// +// Copyright © 2020 QuickBird Studios. All rights reserved. +// + +import Foundation + +/// Source: https://crccalc.com +final class CRC32Tests: CRCTestCase { + + func testCalculatorASCII123456789() { + verifyCalculator(for: "123456789".data(using: .ascii)!, with: [ + .default, + .bzip2, + .jamCRC, + .mpeg2, + .posix, + .sata, + .xfer, + .c, + .d, + .q, + ]) + } + + func testASCII123456789() { + verify(for: "123456789".data(using: .ascii)!, expected: [ + (0xCBF43926, .default), + (0xFC891918, .bzip2), + (0x340BC6D9, .jamCRC), + (0x0376E6E7, .mpeg2), + (0x765E7680, .posix), + (0xCF72AFE8, .sata), + (0xBD0BE338, .xfer), + (0xE3069283, .c), + (0x87315576, .d), + (0x3010BF7F, .q), + ]) + } + + func test0x0204() { + verify(for: Data([0x02, 0x04]), expected: [ + (0x7482B464, .default), + (0x4CBE7351, .bzip2), + (0x8B7D4B9B, .jamCRC), + (0xB3418CAE, .mpeg2), + (0x4C09172C, .posix), + (0xCF91D77D, .sata), + (0x00015CBC, .xfer), + (0x11BED023, .c), + (0xB9F02A25, .d), + (0x0786E39E, .q), + ]) + } + + func testLookupTableDefault() { + verifyLookupTable(for: .default, equalsTo: [ + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, + 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, + 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, + 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, + 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, + 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, + 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, + 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, + 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, + 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, + 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, + 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, + 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, + 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, + 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, + 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, + 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, + 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, + ]) + } + + func testLookupTableBZIP2() { + verifyLookupTable(for: .bzip2, equalsTo: [ + 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005, + 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, + 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, + 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd, + 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, + 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, + 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, + 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, + 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, + 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, + 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, + 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, + 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, + 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, + 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, + 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a, + 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, + 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, + 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b, + 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, + 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, + 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, + 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, + 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, + 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, + 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, + 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, + 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, + 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, + 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, + 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, + 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4, + ]) + } + + func testLookupTableJAMCRC() { + verifyLookupTable(for: .jamCRC, equalsTo: [ + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, + 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, + 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, + 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, + 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, + 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, + 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, + 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, + 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, + 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, + 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, + 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, + 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, + 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, + 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, + 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, + 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, + 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, + ]) + } + + func testLookupTableMPEG2() { + verifyLookupTable(for: .mpeg2, equalsTo: [ + 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005, + 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, + 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, + 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd, + 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, + 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, + 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, + 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, + 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, + 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, + 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, + 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, + 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, + 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, + 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, + 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a, + 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, + 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, + 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b, + 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, + 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, + 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, + 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, + 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, + 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, + 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, + 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, + 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, + 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, + 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, + 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, + 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4, + ]) + } + + func testLookupTablePOSIX() { + verifyLookupTable(for: .posix, equalsTo: [ + 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005, + 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, + 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, + 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd, + 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, + 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, + 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, + 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, + 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, + 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, + 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, + 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, + 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, + 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, + 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, + 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a, + 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, + 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, + 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b, + 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, + 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, + 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, + 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, + 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, + 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, + 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, + 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, + 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, + 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, + 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, + 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, + 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4, + ]) + } + + func testLookupTableSATA() { + verifyLookupTable(for: .sata, equalsTo: [ + 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005, + 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, + 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, + 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd, + 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, + 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, + 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, + 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, + 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, + 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, + 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, + 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, + 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, + 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, + 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, + 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a, + 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, + 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, + 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b, + 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, + 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, + 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, + 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, + 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, + 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, + 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, + 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, + 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, + 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, + 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, + 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, + 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4, + ]) + } + + func testLookupTableXFER() { + verifyLookupTable(for: .xfer, equalsTo: [ + 0x00000000, 0x000000af, 0x0000015e, 0x000001f1, 0x000002bc, 0x00000213, 0x000003e2, 0x0000034d, + 0x00000578, 0x000005d7, 0x00000426, 0x00000489, 0x000007c4, 0x0000076b, 0x0000069a, 0x00000635, + 0x00000af0, 0x00000a5f, 0x00000bae, 0x00000b01, 0x0000084c, 0x000008e3, 0x00000912, 0x000009bd, + 0x00000f88, 0x00000f27, 0x00000ed6, 0x00000e79, 0x00000d34, 0x00000d9b, 0x00000c6a, 0x00000cc5, + 0x000015e0, 0x0000154f, 0x000014be, 0x00001411, 0x0000175c, 0x000017f3, 0x00001602, 0x000016ad, + 0x00001098, 0x00001037, 0x000011c6, 0x00001169, 0x00001224, 0x0000128b, 0x0000137a, 0x000013d5, + 0x00001f10, 0x00001fbf, 0x00001e4e, 0x00001ee1, 0x00001dac, 0x00001d03, 0x00001cf2, 0x00001c5d, + 0x00001a68, 0x00001ac7, 0x00001b36, 0x00001b99, 0x000018d4, 0x0000187b, 0x0000198a, 0x00001925, + 0x00002bc0, 0x00002b6f, 0x00002a9e, 0x00002a31, 0x0000297c, 0x000029d3, 0x00002822, 0x0000288d, + 0x00002eb8, 0x00002e17, 0x00002fe6, 0x00002f49, 0x00002c04, 0x00002cab, 0x00002d5a, 0x00002df5, + 0x00002130, 0x0000219f, 0x0000206e, 0x000020c1, 0x0000238c, 0x00002323, 0x000022d2, 0x0000227d, + 0x00002448, 0x000024e7, 0x00002516, 0x000025b9, 0x000026f4, 0x0000265b, 0x000027aa, 0x00002705, + 0x00003e20, 0x00003e8f, 0x00003f7e, 0x00003fd1, 0x00003c9c, 0x00003c33, 0x00003dc2, 0x00003d6d, + 0x00003b58, 0x00003bf7, 0x00003a06, 0x00003aa9, 0x000039e4, 0x0000394b, 0x000038ba, 0x00003815, + 0x000034d0, 0x0000347f, 0x0000358e, 0x00003521, 0x0000366c, 0x000036c3, 0x00003732, 0x0000379d, + 0x000031a8, 0x00003107, 0x000030f6, 0x00003059, 0x00003314, 0x000033bb, 0x0000324a, 0x000032e5, + 0x00005780, 0x0000572f, 0x000056de, 0x00005671, 0x0000553c, 0x00005593, 0x00005462, 0x000054cd, + 0x000052f8, 0x00005257, 0x000053a6, 0x00005309, 0x00005044, 0x000050eb, 0x0000511a, 0x000051b5, + 0x00005d70, 0x00005ddf, 0x00005c2e, 0x00005c81, 0x00005fcc, 0x00005f63, 0x00005e92, 0x00005e3d, + 0x00005808, 0x000058a7, 0x00005956, 0x000059f9, 0x00005ab4, 0x00005a1b, 0x00005bea, 0x00005b45, + 0x00004260, 0x000042cf, 0x0000433e, 0x00004391, 0x000040dc, 0x00004073, 0x00004182, 0x0000412d, + 0x00004718, 0x000047b7, 0x00004646, 0x000046e9, 0x000045a4, 0x0000450b, 0x000044fa, 0x00004455, + 0x00004890, 0x0000483f, 0x000049ce, 0x00004961, 0x00004a2c, 0x00004a83, 0x00004b72, 0x00004bdd, + 0x00004de8, 0x00004d47, 0x00004cb6, 0x00004c19, 0x00004f54, 0x00004ffb, 0x00004e0a, 0x00004ea5, + 0x00007c40, 0x00007cef, 0x00007d1e, 0x00007db1, 0x00007efc, 0x00007e53, 0x00007fa2, 0x00007f0d, + 0x00007938, 0x00007997, 0x00007866, 0x000078c9, 0x00007b84, 0x00007b2b, 0x00007ada, 0x00007a75, + 0x000076b0, 0x0000761f, 0x000077ee, 0x00007741, 0x0000740c, 0x000074a3, 0x00007552, 0x000075fd, + 0x000073c8, 0x00007367, 0x00007296, 0x00007239, 0x00007174, 0x000071db, 0x0000702a, 0x00007085, + 0x000069a0, 0x0000690f, 0x000068fe, 0x00006851, 0x00006b1c, 0x00006bb3, 0x00006a42, 0x00006aed, + 0x00006cd8, 0x00006c77, 0x00006d86, 0x00006d29, 0x00006e64, 0x00006ecb, 0x00006f3a, 0x00006f95, + 0x00006350, 0x000063ff, 0x0000620e, 0x000062a1, 0x000061ec, 0x00006143, 0x000060b2, 0x0000601d, + 0x00006628, 0x00006687, 0x00006776, 0x000067d9, 0x00006494, 0x0000643b, 0x000065ca, 0x00006565, + ]) + } + + func testLookupTableC() { + verifyLookupTable(for: .c, equalsTo: [ + 0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4, 0xc79a971f, 0x35f1141c, 0x26a1e7e8, 0xd4ca64eb, + 0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b, 0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24, + 0x105ec76f, 0xe235446c, 0xf165b798, 0x030e349b, 0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384, + 0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54, 0x5d1d08bf, 0xaf768bbc, 0xbc267848, 0x4e4dfb4b, + 0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a, 0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35, + 0xaa64d611, 0x580f5512, 0x4b5fa6e6, 0xb93425e5, 0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa, + 0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45, 0xf779deae, 0x05125dad, 0x1642ae59, 0xe4292d5a, + 0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a, 0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595, + 0x417b1dbc, 0xb3109ebf, 0xa0406d4b, 0x522bee48, 0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957, + 0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687, 0x0c38d26c, 0xfe53516f, 0xed03a29b, 0x1f682198, + 0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927, 0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38, + 0xdbfc821c, 0x2997011f, 0x3ac7f2eb, 0xc8ac71e8, 0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7, + 0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096, 0xa65c047d, 0x5437877e, 0x4767748a, 0xb50cf789, + 0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859, 0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46, + 0x7198540d, 0x83f3d70e, 0x90a324fa, 0x62c8a7f9, 0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6, + 0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36, 0x3cdb9bdd, 0xceb018de, 0xdde0eb2a, 0x2f8b6829, + 0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c, 0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93, + 0x082f63b7, 0xfa44e0b4, 0xe9141340, 0x1b7f9043, 0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c, + 0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3, 0x55326b08, 0xa759e80b, 0xb4091bff, 0x466298fc, + 0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c, 0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033, + 0xa24bb5a6, 0x502036a5, 0x4370c551, 0xb11b4652, 0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d, + 0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d, 0xef087a76, 0x1d63f975, 0x0e330a81, 0xfc588982, + 0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d, 0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622, + 0x38cc2a06, 0xcaa7a905, 0xd9f75af1, 0x2b9cd9f2, 0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed, + 0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530, 0x0417b1db, 0xf67c32d8, 0xe52cc12c, 0x1747422f, + 0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff, 0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0, + 0xd3d3e1ab, 0x21b862a8, 0x32e8915c, 0xc083125f, 0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540, + 0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90, 0x9e902e7b, 0x6cfbad78, 0x7fab5e8c, 0x8dc0dd8f, + 0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee, 0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1, + 0x69e9f0d5, 0x9b8273d6, 0x88d28022, 0x7ab90321, 0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e, + 0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81, 0x34f4f86a, 0xc69f7b69, 0xd5cf889d, 0x27a40b9e, + 0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e, 0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351, + ]) + } + + func testLookupTableD() { + verifyLookupTable(for: .d, equalsTo: [ + 0x00000000, 0x2bddd04f, 0x57bba09e, 0x7c6670d1, 0xaf77413c, 0x84aa9173, 0xf8cce1a2, 0xd31131ed, + 0xf6dd1a53, 0xdd00ca1c, 0xa166bacd, 0x8abb6a82, 0x59aa5b6f, 0x72778b20, 0x0e11fbf1, 0x25cc2bbe, + 0x4589ac8d, 0x6e547cc2, 0x12320c13, 0x39efdc5c, 0xeafeedb1, 0xc1233dfe, 0xbd454d2f, 0x96989d60, + 0xb354b6de, 0x98896691, 0xe4ef1640, 0xcf32c60f, 0x1c23f7e2, 0x37fe27ad, 0x4b98577c, 0x60458733, + 0x8b13591a, 0xa0ce8955, 0xdca8f984, 0xf77529cb, 0x24641826, 0x0fb9c869, 0x73dfb8b8, 0x580268f7, + 0x7dce4349, 0x56139306, 0x2a75e3d7, 0x01a83398, 0xd2b90275, 0xf964d23a, 0x8502a2eb, 0xaedf72a4, + 0xce9af597, 0xe54725d8, 0x99215509, 0xb2fc8546, 0x61edb4ab, 0x4a3064e4, 0x36561435, 0x1d8bc47a, + 0x3847efc4, 0x139a3f8b, 0x6ffc4f5a, 0x44219f15, 0x9730aef8, 0xbced7eb7, 0xc08b0e66, 0xeb56de29, + 0xbe152a1f, 0x95c8fa50, 0xe9ae8a81, 0xc2735ace, 0x11626b23, 0x3abfbb6c, 0x46d9cbbd, 0x6d041bf2, + 0x48c8304c, 0x6315e003, 0x1f7390d2, 0x34ae409d, 0xe7bf7170, 0xcc62a13f, 0xb004d1ee, 0x9bd901a1, + 0xfb9c8692, 0xd04156dd, 0xac27260c, 0x87faf643, 0x54ebc7ae, 0x7f3617e1, 0x03506730, 0x288db77f, + 0x0d419cc1, 0x269c4c8e, 0x5afa3c5f, 0x7127ec10, 0xa236ddfd, 0x89eb0db2, 0xf58d7d63, 0xde50ad2c, + 0x35067305, 0x1edba34a, 0x62bdd39b, 0x496003d4, 0x9a713239, 0xb1ace276, 0xcdca92a7, 0xe61742e8, + 0xc3db6956, 0xe806b919, 0x9460c9c8, 0xbfbd1987, 0x6cac286a, 0x4771f825, 0x3b1788f4, 0x10ca58bb, + 0x708fdf88, 0x5b520fc7, 0x27347f16, 0x0ce9af59, 0xdff89eb4, 0xf4254efb, 0x88433e2a, 0xa39eee65, + 0x8652c5db, 0xad8f1594, 0xd1e96545, 0xfa34b50a, 0x292584e7, 0x02f854a8, 0x7e9e2479, 0x5543f436, + 0xd419cc15, 0xffc41c5a, 0x83a26c8b, 0xa87fbcc4, 0x7b6e8d29, 0x50b35d66, 0x2cd52db7, 0x0708fdf8, + 0x22c4d646, 0x09190609, 0x757f76d8, 0x5ea2a697, 0x8db3977a, 0xa66e4735, 0xda0837e4, 0xf1d5e7ab, + 0x91906098, 0xba4db0d7, 0xc62bc006, 0xedf61049, 0x3ee721a4, 0x153af1eb, 0x695c813a, 0x42815175, + 0x674d7acb, 0x4c90aa84, 0x30f6da55, 0x1b2b0a1a, 0xc83a3bf7, 0xe3e7ebb8, 0x9f819b69, 0xb45c4b26, + 0x5f0a950f, 0x74d74540, 0x08b13591, 0x236ce5de, 0xf07dd433, 0xdba0047c, 0xa7c674ad, 0x8c1ba4e2, + 0xa9d78f5c, 0x820a5f13, 0xfe6c2fc2, 0xd5b1ff8d, 0x06a0ce60, 0x2d7d1e2f, 0x511b6efe, 0x7ac6beb1, + 0x1a833982, 0x315ee9cd, 0x4d38991c, 0x66e54953, 0xb5f478be, 0x9e29a8f1, 0xe24fd820, 0xc992086f, + 0xec5e23d1, 0xc783f39e, 0xbbe5834f, 0x90385300, 0x432962ed, 0x68f4b2a2, 0x1492c273, 0x3f4f123c, + 0x6a0ce60a, 0x41d13645, 0x3db74694, 0x166a96db, 0xc57ba736, 0xeea67779, 0x92c007a8, 0xb91dd7e7, + 0x9cd1fc59, 0xb70c2c16, 0xcb6a5cc7, 0xe0b78c88, 0x33a6bd65, 0x187b6d2a, 0x641d1dfb, 0x4fc0cdb4, + 0x2f854a87, 0x04589ac8, 0x783eea19, 0x53e33a56, 0x80f20bbb, 0xab2fdbf4, 0xd749ab25, 0xfc947b6a, + 0xd95850d4, 0xf285809b, 0x8ee3f04a, 0xa53e2005, 0x762f11e8, 0x5df2c1a7, 0x2194b176, 0x0a496139, + 0xe11fbf10, 0xcac26f5f, 0xb6a41f8e, 0x9d79cfc1, 0x4e68fe2c, 0x65b52e63, 0x19d35eb2, 0x320e8efd, + 0x17c2a543, 0x3c1f750c, 0x407905dd, 0x6ba4d592, 0xb8b5e47f, 0x93683430, 0xef0e44e1, 0xc4d394ae, + 0xa496139d, 0x8f4bc3d2, 0xf32db303, 0xd8f0634c, 0x0be152a1, 0x203c82ee, 0x5c5af23f, 0x77872270, + 0x524b09ce, 0x7996d981, 0x05f0a950, 0x2e2d791f, 0xfd3c48f2, 0xd6e198bd, 0xaa87e86c, 0x815a3823, + ]) + } + + func testLookupTableQ() { + verifyLookupTable(for: .q, equalsTo: [ + 0x00000000, 0x814141ab, 0x83c3c2fd, 0x02828356, 0x86c6c451, 0x078785fa, 0x050506ac, 0x84444707, + 0x8cccc909, 0x0d8d88a2, 0x0f0f0bf4, 0x8e4e4a5f, 0x0a0a0d58, 0x8b4b4cf3, 0x89c9cfa5, 0x08888e0e, + 0x98d8d3b9, 0x19999212, 0x1b1b1144, 0x9a5a50ef, 0x1e1e17e8, 0x9f5f5643, 0x9dddd515, 0x1c9c94be, + 0x14141ab0, 0x95555b1b, 0x97d7d84d, 0x169699e6, 0x92d2dee1, 0x13939f4a, 0x11111c1c, 0x90505db7, + 0xb0f0e6d9, 0x31b1a772, 0x33332424, 0xb272658f, 0x36362288, 0xb7776323, 0xb5f5e075, 0x34b4a1de, + 0x3c3c2fd0, 0xbd7d6e7b, 0xbfffed2d, 0x3ebeac86, 0xbafaeb81, 0x3bbbaa2a, 0x3939297c, 0xb87868d7, + 0x28283560, 0xa96974cb, 0xabebf79d, 0x2aaab636, 0xaeeef131, 0x2fafb09a, 0x2d2d33cc, 0xac6c7267, + 0xa4e4fc69, 0x25a5bdc2, 0x27273e94, 0xa6667f3f, 0x22223838, 0xa3637993, 0xa1e1fac5, 0x20a0bb6e, + 0xe0a08c19, 0x61e1cdb2, 0x63634ee4, 0xe2220f4f, 0x66664848, 0xe72709e3, 0xe5a58ab5, 0x64e4cb1e, + 0x6c6c4510, 0xed2d04bb, 0xefaf87ed, 0x6eeec646, 0xeaaa8141, 0x6bebc0ea, 0x696943bc, 0xe8280217, + 0x78785fa0, 0xf9391e0b, 0xfbbb9d5d, 0x7afadcf6, 0xfebe9bf1, 0x7fffda5a, 0x7d7d590c, 0xfc3c18a7, + 0xf4b496a9, 0x75f5d702, 0x77775454, 0xf63615ff, 0x727252f8, 0xf3331353, 0xf1b19005, 0x70f0d1ae, + 0x50506ac0, 0xd1112b6b, 0xd393a83d, 0x52d2e996, 0xd696ae91, 0x57d7ef3a, 0x55556c6c, 0xd4142dc7, + 0xdc9ca3c9, 0x5ddde262, 0x5f5f6134, 0xde1e209f, 0x5a5a6798, 0xdb1b2633, 0xd999a565, 0x58d8e4ce, + 0xc888b979, 0x49c9f8d2, 0x4b4b7b84, 0xca0a3a2f, 0x4e4e7d28, 0xcf0f3c83, 0xcd8dbfd5, 0x4cccfe7e, + 0x44447070, 0xc50531db, 0xc787b28d, 0x46c6f326, 0xc282b421, 0x43c3f58a, 0x414176dc, 0xc0003777, + 0x40005999, 0xc1411832, 0xc3c39b64, 0x4282dacf, 0xc6c69dc8, 0x4787dc63, 0x45055f35, 0xc4441e9e, + 0xcccc9090, 0x4d8dd13b, 0x4f0f526d, 0xce4e13c6, 0x4a0a54c1, 0xcb4b156a, 0xc9c9963c, 0x4888d797, + 0xd8d88a20, 0x5999cb8b, 0x5b1b48dd, 0xda5a0976, 0x5e1e4e71, 0xdf5f0fda, 0xdddd8c8c, 0x5c9ccd27, + 0x54144329, 0xd5550282, 0xd7d781d4, 0x5696c07f, 0xd2d28778, 0x5393c6d3, 0x51114585, 0xd050042e, + 0xf0f0bf40, 0x71b1feeb, 0x73337dbd, 0xf2723c16, 0x76367b11, 0xf7773aba, 0xf5f5b9ec, 0x74b4f847, + 0x7c3c7649, 0xfd7d37e2, 0xffffb4b4, 0x7ebef51f, 0xfafab218, 0x7bbbf3b3, 0x793970e5, 0xf878314e, + 0x68286cf9, 0xe9692d52, 0xebebae04, 0x6aaaefaf, 0xeeeea8a8, 0x6fafe903, 0x6d2d6a55, 0xec6c2bfe, + 0xe4e4a5f0, 0x65a5e45b, 0x6727670d, 0xe66626a6, 0x622261a1, 0xe363200a, 0xe1e1a35c, 0x60a0e2f7, + 0xa0a0d580, 0x21e1942b, 0x2363177d, 0xa22256d6, 0x266611d1, 0xa727507a, 0xa5a5d32c, 0x24e49287, + 0x2c6c1c89, 0xad2d5d22, 0xafafde74, 0x2eee9fdf, 0xaaaad8d8, 0x2beb9973, 0x29691a25, 0xa8285b8e, + 0x38780639, 0xb9394792, 0xbbbbc4c4, 0x3afa856f, 0xbebec268, 0x3fff83c3, 0x3d7d0095, 0xbc3c413e, + 0xb4b4cf30, 0x35f58e9b, 0x37770dcd, 0xb6364c66, 0x32720b61, 0xb3334aca, 0xb1b1c99c, 0x30f08837, + 0x10503359, 0x911172f2, 0x9393f1a4, 0x12d2b00f, 0x9696f708, 0x17d7b6a3, 0x155535f5, 0x9414745e, + 0x9c9cfa50, 0x1dddbbfb, 0x1f5f38ad, 0x9e1e7906, 0x1a5a3e01, 0x9b1b7faa, 0x9999fcfc, 0x18d8bd57, + 0x8888e0e0, 0x09c9a14b, 0x0b4b221d, 0x8a0a63b6, 0x0e4e24b1, 0x8f0f651a, 0x8d8de64c, 0x0ccca7e7, + 0x044429e9, 0x85056842, 0x8787eb14, 0x06c6aabf, 0x8282edb8, 0x03c3ac13, 0x01412f45, 0x80006eee, + ]) + } + +} diff --git a/Tests/CRC64Tests.swift b/Tests/CRC64Tests.swift new file mode 100644 index 0000000..f80b8da --- /dev/null +++ b/Tests/CRC64Tests.swift @@ -0,0 +1,108 @@ +// +// CRC64Tests.swift +// +// Copyright © 2020 QuickBird Studios. All rights reserved. +// + +import Foundation +import CRC + +final class CRC64Tests: CRCTestCase { + + func testCalculatorASCII123456789() { + verifyCalculator(for: "123456789".data(using: .ascii)!, with: [.ecma, .iso]) + } + + /// Source: https://toolkitbay.com/tkb/tool/CRC-64 + func testASCII123456789() { + verify(for: "123456789".data(using: .ascii)!, expected: [ + (0x995DC9BBDF1939FA, .ecma), + (0xB90956C775A41001, .iso), + ]) + } + + /// Source: https://toolkitbay.com/tkb/tool/CRC-64 + func test0x0204() { + verify(for: "987654321".data(using: .ascii)!, expected: [ + (0xE7ADEF3D663C7E22, .ecma), + (0x3CAFB00415A776CF, .iso), + ]) + } + + /// Source: https://github.com/rawrunprotected/crc/blob/master/crc64.c + func testLookupTableECMA() { + verifyLookupTable(for: .ecma, equalsTo: [ + 0x0000000000000000, 0xB32E4CBE03A75F6F, 0xF4843657A840A05B, 0x47AA7AE9ABE7FF34, 0x7BD0C384FF8F5E33, 0xC8FE8F3AFC28015C, 0x8F54F5D357CFFE68, 0x3C7AB96D5468A107, + 0xF7A18709FF1EBC66, 0x448FCBB7FCB9E309, 0x0325B15E575E1C3D, 0xB00BFDE054F94352, 0x8C71448D0091E255, 0x3F5F08330336BD3A, 0x78F572DAA8D1420E, 0xCBDB3E64AB761D61, + 0x7D9BA13851336649, 0xCEB5ED8652943926, 0x891F976FF973C612, 0x3A31DBD1FAD4997D, 0x064B62BCAEBC387A, 0xB5652E02AD1B6715, 0xF2CF54EB06FC9821, 0x41E11855055BC74E, + 0x8A3A2631AE2DDA2F, 0x39146A8FAD8A8540, 0x7EBE1066066D7A74, 0xCD905CD805CA251B, 0xF1EAE5B551A2841C, 0x42C4A90B5205DB73, 0x056ED3E2F9E22447, 0xB6409F5CFA457B28, + 0xFB374270A266CC92, 0x48190ECEA1C193FD, 0x0FB374270A266CC9, 0xBC9D3899098133A6, 0x80E781F45DE992A1, 0x33C9CD4A5E4ECDCE, 0x7463B7A3F5A932FA, 0xC74DFB1DF60E6D95, + 0x0C96C5795D7870F4, 0xBFB889C75EDF2F9B, 0xF812F32EF538D0AF, 0x4B3CBF90F69F8FC0, 0x774606FDA2F72EC7, 0xC4684A43A15071A8, 0x83C230AA0AB78E9C, 0x30EC7C140910D1F3, + 0x86ACE348F355AADB, 0x3582AFF6F0F2F5B4, 0x7228D51F5B150A80, 0xC10699A158B255EF, 0xFD7C20CC0CDAF4E8, 0x4E526C720F7DAB87, 0x09F8169BA49A54B3, 0xBAD65A25A73D0BDC, + 0x710D64410C4B16BD, 0xC22328FF0FEC49D2, 0x85895216A40BB6E6, 0x36A71EA8A7ACE989, 0x0ADDA7C5F3C4488E, 0xB9F3EB7BF06317E1, 0xFE5991925B84E8D5, 0x4D77DD2C5823B7BA, + 0x64B62BCAEBC387A1, 0xD7986774E864D8CE, 0x90321D9D438327FA, 0x231C512340247895, 0x1F66E84E144CD992, 0xAC48A4F017EB86FD, 0xEBE2DE19BC0C79C9, 0x58CC92A7BFAB26A6, + 0x9317ACC314DD3BC7, 0x2039E07D177A64A8, 0x67939A94BC9D9B9C, 0xD4BDD62ABF3AC4F3, 0xE8C76F47EB5265F4, 0x5BE923F9E8F53A9B, 0x1C4359104312C5AF, 0xAF6D15AE40B59AC0, + 0x192D8AF2BAF0E1E8, 0xAA03C64CB957BE87, 0xEDA9BCA512B041B3, 0x5E87F01B11171EDC, 0x62FD4976457FBFDB, 0xD1D305C846D8E0B4, 0x96797F21ED3F1F80, 0x2557339FEE9840EF, + 0xEE8C0DFB45EE5D8E, 0x5DA24145464902E1, 0x1A083BACEDAEFDD5, 0xA9267712EE09A2BA, 0x955CCE7FBA6103BD, 0x267282C1B9C65CD2, 0x61D8F8281221A3E6, 0xD2F6B4961186FC89, + 0x9F8169BA49A54B33, 0x2CAF25044A02145C, 0x6B055FEDE1E5EB68, 0xD82B1353E242B407, 0xE451AA3EB62A1500, 0x577FE680B58D4A6F, 0x10D59C691E6AB55B, 0xA3FBD0D71DCDEA34, + 0x6820EEB3B6BBF755, 0xDB0EA20DB51CA83A, 0x9CA4D8E41EFB570E, 0x2F8A945A1D5C0861, 0x13F02D374934A966, 0xA0DE61894A93F609, 0xE7741B60E174093D, 0x545A57DEE2D35652, + 0xE21AC88218962D7A, 0x5134843C1B317215, 0x169EFED5B0D68D21, 0xA5B0B26BB371D24E, 0x99CA0B06E7197349, 0x2AE447B8E4BE2C26, 0x6D4E3D514F59D312, 0xDE6071EF4CFE8C7D, + 0x15BB4F8BE788911C, 0xA6950335E42FCE73, 0xE13F79DC4FC83147, 0x521135624C6F6E28, 0x6E6B8C0F1807CF2F, 0xDD45C0B11BA09040, 0x9AEFBA58B0476F74, 0x29C1F6E6B3E0301B, + 0xC96C5795D7870F42, 0x7A421B2BD420502D, 0x3DE861C27FC7AF19, 0x8EC62D7C7C60F076, 0xB2BC941128085171, 0x0192D8AF2BAF0E1E, 0x4638A2468048F12A, 0xF516EEF883EFAE45, + 0x3ECDD09C2899B324, 0x8DE39C222B3EEC4B, 0xCA49E6CB80D9137F, 0x7967AA75837E4C10, 0x451D1318D716ED17, 0xF6335FA6D4B1B278, 0xB199254F7F564D4C, 0x02B769F17CF11223, + 0xB4F7F6AD86B4690B, 0x07D9BA1385133664, 0x4073C0FA2EF4C950, 0xF35D8C442D53963F, 0xCF273529793B3738, 0x7C0979977A9C6857, 0x3BA3037ED17B9763, 0x888D4FC0D2DCC80C, + 0x435671A479AAD56D, 0xF0783D1A7A0D8A02, 0xB7D247F3D1EA7536, 0x04FC0B4DD24D2A59, 0x3886B22086258B5E, 0x8BA8FE9E8582D431, 0xCC0284772E652B05, 0x7F2CC8C92DC2746A, + 0x325B15E575E1C3D0, 0x8175595B76469CBF, 0xC6DF23B2DDA1638B, 0x75F16F0CDE063CE4, 0x498BD6618A6E9DE3, 0xFAA59ADF89C9C28C, 0xBD0FE036222E3DB8, 0x0E21AC88218962D7, + 0xC5FA92EC8AFF7FB6, 0x76D4DE52895820D9, 0x317EA4BB22BFDFED, 0x8250E80521188082, 0xBE2A516875702185, 0x0D041DD676D77EEA, 0x4AAE673FDD3081DE, 0xF9802B81DE97DEB1, + 0x4FC0B4DD24D2A599, 0xFCEEF8632775FAF6, 0xBB44828A8C9205C2, 0x086ACE348F355AAD, 0x34107759DB5DFBAA, 0x873E3BE7D8FAA4C5, 0xC094410E731D5BF1, 0x73BA0DB070BA049E, + 0xB86133D4DBCC19FF, 0x0B4F7F6AD86B4690, 0x4CE50583738CB9A4, 0xFFCB493D702BE6CB, 0xC3B1F050244347CC, 0x709FBCEE27E418A3, 0x3735C6078C03E797, 0x841B8AB98FA4B8F8, + 0xADDA7C5F3C4488E3, 0x1EF430E13FE3D78C, 0x595E4A08940428B8, 0xEA7006B697A377D7, 0xD60ABFDBC3CBD6D0, 0x6524F365C06C89BF, 0x228E898C6B8B768B, 0x91A0C532682C29E4, + 0x5A7BFB56C35A3485, 0xE955B7E8C0FD6BEA, 0xAEFFCD016B1A94DE, 0x1DD181BF68BDCBB1, 0x21AB38D23CD56AB6, 0x9285746C3F7235D9, 0xD52F0E859495CAED, 0x6601423B97329582, + 0xD041DD676D77EEAA, 0x636F91D96ED0B1C5, 0x24C5EB30C5374EF1, 0x97EBA78EC690119E, 0xAB911EE392F8B099, 0x18BF525D915FEFF6, 0x5F1528B43AB810C2, 0xEC3B640A391F4FAD, + 0x27E05A6E926952CC, 0x94CE16D091CE0DA3, 0xD3646C393A29F297, 0x604A2087398EADF8, 0x5C3099EA6DE60CFF, 0xEF1ED5546E415390, 0xA8B4AFBDC5A6ACA4, 0x1B9AE303C601F3CB, + 0x56ED3E2F9E224471, 0xE5C372919D851B1E, 0xA26908783662E42A, 0x114744C635C5BB45, 0x2D3DFDAB61AD1A42, 0x9E13B115620A452D, 0xD9B9CBFCC9EDBA19, 0x6A978742CA4AE576, + 0xA14CB926613CF817, 0x1262F598629BA778, 0x55C88F71C97C584C, 0xE6E6C3CFCADB0723, 0xDA9C7AA29EB3A624, 0x69B2361C9D14F94B, 0x2E184CF536F3067F, 0x9D36004B35545910, + 0x2B769F17CF112238, 0x9858D3A9CCB67D57, 0xDFF2A94067518263, 0x6CDCE5FE64F6DD0C, 0x50A65C93309E7C0B, 0xE388102D33392364, 0xA4226AC498DEDC50, 0x170C267A9B79833F, + 0xDCD7181E300F9E5E, 0x6FF954A033A8C131, 0x28532E49984F3E05, 0x9B7D62F79BE8616A, 0xA707DB9ACF80C06D, 0x14299724CC279F02, 0x5383EDCD67C06036, 0xE0ADA17364673F59, + ]) + } + + /// Source: https://www.rubydoc.info/gems/digest-crc/Digest/CRC64 + func testLookupTableISO() { + verifyLookupTable(for: .iso, equalsTo: [ + 0x0000000000000000, 0x01B0000000000000, 0x0360000000000000, 0x02D0000000000000, 0x06C0000000000000, 0x0770000000000000, 0x05A0000000000000, 0x0410000000000000, + 0x0D80000000000000, 0x0C30000000000000, 0x0EE0000000000000, 0x0F50000000000000, 0x0B40000000000000, 0x0AF0000000000000, 0x0820000000000000, 0x0990000000000000, + 0x1B00000000000000, 0x1AB0000000000000, 0x1860000000000000, 0x19D0000000000000, 0x1DC0000000000000, 0x1C70000000000000, 0x1EA0000000000000, 0x1F10000000000000, + 0x1680000000000000, 0x1730000000000000, 0x15E0000000000000, 0x1450000000000000, 0x1040000000000000, 0x11F0000000000000, 0x1320000000000000, 0x1290000000000000, + 0x3600000000000000, 0x37B0000000000000, 0x3560000000000000, 0x34D0000000000000, 0x30C0000000000000, 0x3170000000000000, 0x33A0000000000000, 0x3210000000000000, + 0x3B80000000000000, 0x3A30000000000000, 0x38E0000000000000, 0x3950000000000000, 0x3D40000000000000, 0x3CF0000000000000, 0x3E20000000000000, 0x3F90000000000000, + 0x2D00000000000000, 0x2CB0000000000000, 0x2E60000000000000, 0x2FD0000000000000, 0x2BC0000000000000, 0x2A70000000000000, 0x28A0000000000000, 0x2910000000000000, + 0x2080000000000000, 0x2130000000000000, 0x23E0000000000000, 0x2250000000000000, 0x2640000000000000, 0x27F0000000000000, 0x2520000000000000, 0x2490000000000000, + 0x6C00000000000000, 0x6DB0000000000000, 0x6F60000000000000, 0x6ED0000000000000, 0x6AC0000000000000, 0x6B70000000000000, 0x69A0000000000000, 0x6810000000000000, + 0x6180000000000000, 0x6030000000000000, 0x62E0000000000000, 0x6350000000000000, 0x6740000000000000, 0x66F0000000000000, 0x6420000000000000, 0x6590000000000000, + 0x7700000000000000, 0x76B0000000000000, 0x7460000000000000, 0x75D0000000000000, 0x71C0000000000000, 0x7070000000000000, 0x72A0000000000000, 0x7310000000000000, + 0x7A80000000000000, 0x7B30000000000000, 0x79E0000000000000, 0x7850000000000000, 0x7C40000000000000, 0x7DF0000000000000, 0x7F20000000000000, 0x7E90000000000000, + 0x5A00000000000000, 0x5BB0000000000000, 0x5960000000000000, 0x58D0000000000000, 0x5CC0000000000000, 0x5D70000000000000, 0x5FA0000000000000, 0x5E10000000000000, + 0x5780000000000000, 0x5630000000000000, 0x54E0000000000000, 0x5550000000000000, 0x5140000000000000, 0x50F0000000000000, 0x5220000000000000, 0x5390000000000000, + 0x4100000000000000, 0x40B0000000000000, 0x4260000000000000, 0x43D0000000000000, 0x47C0000000000000, 0x4670000000000000, 0x44A0000000000000, 0x4510000000000000, + 0x4C80000000000000, 0x4D30000000000000, 0x4FE0000000000000, 0x4E50000000000000, 0x4A40000000000000, 0x4BF0000000000000, 0x4920000000000000, 0x4890000000000000, + 0xD800000000000000, 0xD9B0000000000000, 0xDB60000000000000, 0xDAD0000000000000, 0xDEC0000000000000, 0xDF70000000000000, 0xDDA0000000000000, 0xDC10000000000000, + 0xD580000000000000, 0xD430000000000000, 0xD6E0000000000000, 0xD750000000000000, 0xD340000000000000, 0xD2F0000000000000, 0xD020000000000000, 0xD190000000000000, + 0xC300000000000000, 0xC2B0000000000000, 0xC060000000000000, 0xC1D0000000000000, 0xC5C0000000000000, 0xC470000000000000, 0xC6A0000000000000, 0xC710000000000000, + 0xCE80000000000000, 0xCF30000000000000, 0xCDE0000000000000, 0xCC50000000000000, 0xC840000000000000, 0xC9F0000000000000, 0xCB20000000000000, 0xCA90000000000000, + 0xEE00000000000000, 0xEFB0000000000000, 0xED60000000000000, 0xECD0000000000000, 0xE8C0000000000000, 0xE970000000000000, 0xEBA0000000000000, 0xEA10000000000000, + 0xE380000000000000, 0xE230000000000000, 0xE0E0000000000000, 0xE150000000000000, 0xE540000000000000, 0xE4F0000000000000, 0xE620000000000000, 0xE790000000000000, + 0xF500000000000000, 0xF4B0000000000000, 0xF660000000000000, 0xF7D0000000000000, 0xF3C0000000000000, 0xF270000000000000, 0xF0A0000000000000, 0xF110000000000000, + 0xF880000000000000, 0xF930000000000000, 0xFBE0000000000000, 0xFA50000000000000, 0xFE40000000000000, 0xFFF0000000000000, 0xFD20000000000000, 0xFC90000000000000, + 0xB400000000000000, 0xB5B0000000000000, 0xB760000000000000, 0xB6D0000000000000, 0xB2C0000000000000, 0xB370000000000000, 0xB1A0000000000000, 0xB010000000000000, + 0xB980000000000000, 0xB830000000000000, 0xBAE0000000000000, 0xBB50000000000000, 0xBF40000000000000, 0xBEF0000000000000, 0xBC20000000000000, 0xBD90000000000000, + 0xAF00000000000000, 0xAEB0000000000000, 0xAC60000000000000, 0xADD0000000000000, 0xA9C0000000000000, 0xA870000000000000, 0xAAA0000000000000, 0xAB10000000000000, + 0xA280000000000000, 0xA330000000000000, 0xA1E0000000000000, 0xA050000000000000, 0xA440000000000000, 0xA5F0000000000000, 0xA720000000000000, 0xA690000000000000, + 0x8200000000000000, 0x83B0000000000000, 0x8160000000000000, 0x80D0000000000000, 0x84C0000000000000, 0x8570000000000000, 0x87A0000000000000, 0x8610000000000000, + 0x8F80000000000000, 0x8E30000000000000, 0x8CE0000000000000, 0x8D50000000000000, 0x8940000000000000, 0x88F0000000000000, 0x8A20000000000000, 0x8B90000000000000, + 0x9900000000000000, 0x98B0000000000000, 0x9A60000000000000, 0x9BD0000000000000, 0x9FC0000000000000, 0x9E70000000000000, 0x9CA0000000000000, 0x9D10000000000000, + 0x9480000000000000, 0x9530000000000000, 0x97E0000000000000, 0x9650000000000000, 0x9240000000000000, 0x93F0000000000000, 0x9120000000000000, 0x9090000000000000, + ]) + } + +} diff --git a/Tests/CRC8Tests.swift b/Tests/CRC8Tests.swift new file mode 100644 index 0000000..4288214 --- /dev/null +++ b/Tests/CRC8Tests.swift @@ -0,0 +1,430 @@ +// +// CRC8Tests.swift +// +// Copyright © 2020 QuickBird Studios. All rights reserved. +// + +import Foundation + +/// Source: https://crccalc.com +final class CRC8Tests: CRCTestCase { + + func testCalculatorASCII123456789() { + verifyCalculator( + for: "123456789".data(using: .ascii)!, + with: [ + .default, + .cdma2000, + .darc, + .dvbS2, + .ebu, + .iCode, + .itu, + .maxim, + .rohc, + .wcdma, + ] + ) + } + + func testASCII123456789() { + verify(for: "123456789".data(using: .ascii)!, expected: [ + (0xF4, .default), + (0xDA, .cdma2000), + (0x15, .darc), + (0xBC, .dvbS2), + (0x97, .ebu), + (0x7E, .iCode), + (0xA1, .itu), + (0xA1, .maxim), + (0xD0, .rohc), + (0x25, .wcdma), + ]) + } + + func test0x0204() { + verify(for: Data([0x02, 0x04]), expected: [ + (0x36, .default), + (0x5C, .cdma2000), + (0xF5, .darc), + (0xE8, .dvbS2), + (0x34, .ebu), + (0x35, .iCode), + (0x63, .itu), + (0xF0, .maxim), + (0x36, .rohc), + (0x7D, .wcdma), + ]) + } + + func testLookupTableCDMA2000() throws { + verifyLookupTable(for: .cdma2000, equalsTo: [ + 0x00, 0x9b, 0xad, 0x36, 0xc1, 0x5a, 0x6c, 0xf7, + 0x19, 0x82, 0xb4, 0x2f, 0xd8, 0x43, 0x75, 0xee, + 0x32, 0xa9, 0x9f, 0x04, 0xf3, 0x68, 0x5e, 0xc5, + 0x2b, 0xb0, 0x86, 0x1d, 0xea, 0x71, 0x47, 0xdc, + 0x64, 0xff, 0xc9, 0x52, 0xa5, 0x3e, 0x08, 0x93, + 0x7d, 0xe6, 0xd0, 0x4b, 0xbc, 0x27, 0x11, 0x8a, + 0x56, 0xcd, 0xfb, 0x60, 0x97, 0x0c, 0x3a, 0xa1, + 0x4f, 0xd4, 0xe2, 0x79, 0x8e, 0x15, 0x23, 0xb8, + 0xc8, 0x53, 0x65, 0xfe, 0x09, 0x92, 0xa4, 0x3f, + 0xd1, 0x4a, 0x7c, 0xe7, 0x10, 0x8b, 0xbd, 0x26, + 0xfa, 0x61, 0x57, 0xcc, 0x3b, 0xa0, 0x96, 0x0d, + 0xe3, 0x78, 0x4e, 0xd5, 0x22, 0xb9, 0x8f, 0x14, + 0xac, 0x37, 0x01, 0x9a, 0x6d, 0xf6, 0xc0, 0x5b, + 0xb5, 0x2e, 0x18, 0x83, 0x74, 0xef, 0xd9, 0x42, + 0x9e, 0x05, 0x33, 0xa8, 0x5f, 0xc4, 0xf2, 0x69, + 0x87, 0x1c, 0x2a, 0xb1, 0x46, 0xdd, 0xeb, 0x70, + 0x0b, 0x90, 0xa6, 0x3d, 0xca, 0x51, 0x67, 0xfc, + 0x12, 0x89, 0xbf, 0x24, 0xd3, 0x48, 0x7e, 0xe5, + 0x39, 0xa2, 0x94, 0x0f, 0xf8, 0x63, 0x55, 0xce, + 0x20, 0xbb, 0x8d, 0x16, 0xe1, 0x7a, 0x4c, 0xd7, + 0x6f, 0xf4, 0xc2, 0x59, 0xae, 0x35, 0x03, 0x98, + 0x76, 0xed, 0xdb, 0x40, 0xb7, 0x2c, 0x1a, 0x81, + 0x5d, 0xc6, 0xf0, 0x6b, 0x9c, 0x07, 0x31, 0xaa, + 0x44, 0xdf, 0xe9, 0x72, 0x85, 0x1e, 0x28, 0xb3, + 0xc3, 0x58, 0x6e, 0xf5, 0x02, 0x99, 0xaf, 0x34, + 0xda, 0x41, 0x77, 0xec, 0x1b, 0x80, 0xb6, 0x2d, + 0xf1, 0x6a, 0x5c, 0xc7, 0x30, 0xab, 0x9d, 0x06, + 0xe8, 0x73, 0x45, 0xde, 0x29, 0xb2, 0x84, 0x1f, + 0xa7, 0x3c, 0x0a, 0x91, 0x66, 0xfd, 0xcb, 0x50, + 0xbe, 0x25, 0x13, 0x88, 0x7f, 0xe4, 0xd2, 0x49, + 0x95, 0x0e, 0x38, 0xa3, 0x54, 0xcf, 0xf9, 0x62, + 0x8c, 0x17, 0x21, 0xba, 0x4d, 0xd6, 0xe0, 0x7b, + ]) + } + + func testLookupTableDefault() throws { + verifyLookupTable(for: .default, equalsTo: [ + 0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15, + 0x38, 0x3f, 0x36, 0x31, 0x24, 0x23, 0x2a, 0x2d, + 0x70, 0x77, 0x7e, 0x79, 0x6c, 0x6b, 0x62, 0x65, + 0x48, 0x4f, 0x46, 0x41, 0x54, 0x53, 0x5a, 0x5d, + 0xe0, 0xe7, 0xee, 0xe9, 0xfc, 0xfb, 0xf2, 0xf5, + 0xd8, 0xdf, 0xd6, 0xd1, 0xc4, 0xc3, 0xca, 0xcd, + 0x90, 0x97, 0x9e, 0x99, 0x8c, 0x8b, 0x82, 0x85, + 0xa8, 0xaf, 0xa6, 0xa1, 0xb4, 0xb3, 0xba, 0xbd, + 0xc7, 0xc0, 0xc9, 0xce, 0xdb, 0xdc, 0xd5, 0xd2, + 0xff, 0xf8, 0xf1, 0xf6, 0xe3, 0xe4, 0xed, 0xea, + 0xb7, 0xb0, 0xb9, 0xbe, 0xab, 0xac, 0xa5, 0xa2, + 0x8f, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9d, 0x9a, + 0x27, 0x20, 0x29, 0x2e, 0x3b, 0x3c, 0x35, 0x32, + 0x1f, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0d, 0x0a, + 0x57, 0x50, 0x59, 0x5e, 0x4b, 0x4c, 0x45, 0x42, + 0x6f, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7d, 0x7a, + 0x89, 0x8e, 0x87, 0x80, 0x95, 0x92, 0x9b, 0x9c, + 0xb1, 0xb6, 0xbf, 0xb8, 0xad, 0xaa, 0xa3, 0xa4, + 0xf9, 0xfe, 0xf7, 0xf0, 0xe5, 0xe2, 0xeb, 0xec, + 0xc1, 0xc6, 0xcf, 0xc8, 0xdd, 0xda, 0xd3, 0xd4, + 0x69, 0x6e, 0x67, 0x60, 0x75, 0x72, 0x7b, 0x7c, + 0x51, 0x56, 0x5f, 0x58, 0x4d, 0x4a, 0x43, 0x44, + 0x19, 0x1e, 0x17, 0x10, 0x05, 0x02, 0x0b, 0x0c, + 0x21, 0x26, 0x2f, 0x28, 0x3d, 0x3a, 0x33, 0x34, + 0x4e, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5c, 0x5b, + 0x76, 0x71, 0x78, 0x7f, 0x6a, 0x6d, 0x64, 0x63, + 0x3e, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2c, 0x2b, + 0x06, 0x01, 0x08, 0x0f, 0x1a, 0x1d, 0x14, 0x13, + 0xae, 0xa9, 0xa0, 0xa7, 0xb2, 0xb5, 0xbc, 0xbb, + 0x96, 0x91, 0x98, 0x9f, 0x8a, 0x8d, 0x84, 0x83, + 0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc, 0xcb, + 0xe6, 0xe1, 0xe8, 0xef, 0xfa, 0xfd, 0xf4, 0xf3, + ]) + } + + func testLookupTableDARC() throws { + verifyLookupTable(for: .darc, equalsTo: [ + 0x00, 0x72, 0xe4, 0x96, 0xf1, 0x83, 0x15, 0x67, + 0xdb, 0xa9, 0x3f, 0x4d, 0x2a, 0x58, 0xce, 0xbc, + 0x8f, 0xfd, 0x6b, 0x19, 0x7e, 0x0c, 0x9a, 0xe8, + 0x54, 0x26, 0xb0, 0xc2, 0xa5, 0xd7, 0x41, 0x33, + 0x27, 0x55, 0xc3, 0xb1, 0xd6, 0xa4, 0x32, 0x40, + 0xfc, 0x8e, 0x18, 0x6a, 0x0d, 0x7f, 0xe9, 0x9b, + 0xa8, 0xda, 0x4c, 0x3e, 0x59, 0x2b, 0xbd, 0xcf, + 0x73, 0x01, 0x97, 0xe5, 0x82, 0xf0, 0x66, 0x14, + 0x4e, 0x3c, 0xaa, 0xd8, 0xbf, 0xcd, 0x5b, 0x29, + 0x95, 0xe7, 0x71, 0x03, 0x64, 0x16, 0x80, 0xf2, + 0xc1, 0xb3, 0x25, 0x57, 0x30, 0x42, 0xd4, 0xa6, + 0x1a, 0x68, 0xfe, 0x8c, 0xeb, 0x99, 0x0f, 0x7d, + 0x69, 0x1b, 0x8d, 0xff, 0x98, 0xea, 0x7c, 0x0e, + 0xb2, 0xc0, 0x56, 0x24, 0x43, 0x31, 0xa7, 0xd5, + 0xe6, 0x94, 0x02, 0x70, 0x17, 0x65, 0xf3, 0x81, + 0x3d, 0x4f, 0xd9, 0xab, 0xcc, 0xbe, 0x28, 0x5a, + 0x9c, 0xee, 0x78, 0x0a, 0x6d, 0x1f, 0x89, 0xfb, + 0x47, 0x35, 0xa3, 0xd1, 0xb6, 0xc4, 0x52, 0x20, + 0x13, 0x61, 0xf7, 0x85, 0xe2, 0x90, 0x06, 0x74, + 0xc8, 0xba, 0x2c, 0x5e, 0x39, 0x4b, 0xdd, 0xaf, + 0xbb, 0xc9, 0x5f, 0x2d, 0x4a, 0x38, 0xae, 0xdc, + 0x60, 0x12, 0x84, 0xf6, 0x91, 0xe3, 0x75, 0x07, + 0x34, 0x46, 0xd0, 0xa2, 0xc5, 0xb7, 0x21, 0x53, + 0xef, 0x9d, 0x0b, 0x79, 0x1e, 0x6c, 0xfa, 0x88, + 0xd2, 0xa0, 0x36, 0x44, 0x23, 0x51, 0xc7, 0xb5, + 0x09, 0x7b, 0xed, 0x9f, 0xf8, 0x8a, 0x1c, 0x6e, + 0x5d, 0x2f, 0xb9, 0xcb, 0xac, 0xde, 0x48, 0x3a, + 0x86, 0xf4, 0x62, 0x10, 0x77, 0x05, 0x93, 0xe1, + 0xf5, 0x87, 0x11, 0x63, 0x04, 0x76, 0xe0, 0x92, + 0x2e, 0x5c, 0xca, 0xb8, 0xdf, 0xad, 0x3b, 0x49, + 0x7a, 0x08, 0x9e, 0xec, 0x8b, 0xf9, 0x6f, 0x1d, + 0xa1, 0xd3, 0x45, 0x37, 0x50, 0x22, 0xb4, 0xc6, + ]) + } + + func testLookupTableDVBS2() throws { + verifyLookupTable(for: .dvbS2, equalsTo: [ + 0x00, 0xd5, 0x7f, 0xaa, 0xfe, 0x2b, 0x81, 0x54, + 0x29, 0xfc, 0x56, 0x83, 0xd7, 0x02, 0xa8, 0x7d, + 0x52, 0x87, 0x2d, 0xf8, 0xac, 0x79, 0xd3, 0x06, + 0x7b, 0xae, 0x04, 0xd1, 0x85, 0x50, 0xfa, 0x2f, + 0xa4, 0x71, 0xdb, 0x0e, 0x5a, 0x8f, 0x25, 0xf0, + 0x8d, 0x58, 0xf2, 0x27, 0x73, 0xa6, 0x0c, 0xd9, + 0xf6, 0x23, 0x89, 0x5c, 0x08, 0xdd, 0x77, 0xa2, + 0xdf, 0x0a, 0xa0, 0x75, 0x21, 0xf4, 0x5e, 0x8b, + 0x9d, 0x48, 0xe2, 0x37, 0x63, 0xb6, 0x1c, 0xc9, + 0xb4, 0x61, 0xcb, 0x1e, 0x4a, 0x9f, 0x35, 0xe0, + 0xcf, 0x1a, 0xb0, 0x65, 0x31, 0xe4, 0x4e, 0x9b, + 0xe6, 0x33, 0x99, 0x4c, 0x18, 0xcd, 0x67, 0xb2, + 0x39, 0xec, 0x46, 0x93, 0xc7, 0x12, 0xb8, 0x6d, + 0x10, 0xc5, 0x6f, 0xba, 0xee, 0x3b, 0x91, 0x44, + 0x6b, 0xbe, 0x14, 0xc1, 0x95, 0x40, 0xea, 0x3f, + 0x42, 0x97, 0x3d, 0xe8, 0xbc, 0x69, 0xc3, 0x16, + 0xef, 0x3a, 0x90, 0x45, 0x11, 0xc4, 0x6e, 0xbb, + 0xc6, 0x13, 0xb9, 0x6c, 0x38, 0xed, 0x47, 0x92, + 0xbd, 0x68, 0xc2, 0x17, 0x43, 0x96, 0x3c, 0xe9, + 0x94, 0x41, 0xeb, 0x3e, 0x6a, 0xbf, 0x15, 0xc0, + 0x4b, 0x9e, 0x34, 0xe1, 0xb5, 0x60, 0xca, 0x1f, + 0x62, 0xb7, 0x1d, 0xc8, 0x9c, 0x49, 0xe3, 0x36, + 0x19, 0xcc, 0x66, 0xb3, 0xe7, 0x32, 0x98, 0x4d, + 0x30, 0xe5, 0x4f, 0x9a, 0xce, 0x1b, 0xb1, 0x64, + 0x72, 0xa7, 0x0d, 0xd8, 0x8c, 0x59, 0xf3, 0x26, + 0x5b, 0x8e, 0x24, 0xf1, 0xa5, 0x70, 0xda, 0x0f, + 0x20, 0xf5, 0x5f, 0x8a, 0xde, 0x0b, 0xa1, 0x74, + 0x09, 0xdc, 0x76, 0xa3, 0xf7, 0x22, 0x88, 0x5d, + 0xd6, 0x03, 0xa9, 0x7c, 0x28, 0xfd, 0x57, 0x82, + 0xff, 0x2a, 0x80, 0x55, 0x01, 0xd4, 0x7e, 0xab, + 0x84, 0x51, 0xfb, 0x2e, 0x7a, 0xaf, 0x05, 0xd0, + 0xad, 0x78, 0xd2, 0x07, 0x53, 0x86, 0x2c, 0xf9, + ]) + } + + func testLookupTableEBU() throws { + verifyLookupTable(for: .ebu, equalsTo: [ + 0x00, 0x64, 0xc8, 0xac, 0xe1, 0x85, 0x29, 0x4d, + 0xb3, 0xd7, 0x7b, 0x1f, 0x52, 0x36, 0x9a, 0xfe, + 0x17, 0x73, 0xdf, 0xbb, 0xf6, 0x92, 0x3e, 0x5a, + 0xa4, 0xc0, 0x6c, 0x08, 0x45, 0x21, 0x8d, 0xe9, + 0x2e, 0x4a, 0xe6, 0x82, 0xcf, 0xab, 0x07, 0x63, + 0x9d, 0xf9, 0x55, 0x31, 0x7c, 0x18, 0xb4, 0xd0, + 0x39, 0x5d, 0xf1, 0x95, 0xd8, 0xbc, 0x10, 0x74, + 0x8a, 0xee, 0x42, 0x26, 0x6b, 0x0f, 0xa3, 0xc7, + 0x5c, 0x38, 0x94, 0xf0, 0xbd, 0xd9, 0x75, 0x11, + 0xef, 0x8b, 0x27, 0x43, 0x0e, 0x6a, 0xc6, 0xa2, + 0x4b, 0x2f, 0x83, 0xe7, 0xaa, 0xce, 0x62, 0x06, + 0xf8, 0x9c, 0x30, 0x54, 0x19, 0x7d, 0xd1, 0xb5, + 0x72, 0x16, 0xba, 0xde, 0x93, 0xf7, 0x5b, 0x3f, + 0xc1, 0xa5, 0x09, 0x6d, 0x20, 0x44, 0xe8, 0x8c, + 0x65, 0x01, 0xad, 0xc9, 0x84, 0xe0, 0x4c, 0x28, + 0xd6, 0xb2, 0x1e, 0x7a, 0x37, 0x53, 0xff, 0x9b, + 0xb8, 0xdc, 0x70, 0x14, 0x59, 0x3d, 0x91, 0xf5, + 0x0b, 0x6f, 0xc3, 0xa7, 0xea, 0x8e, 0x22, 0x46, + 0xaf, 0xcb, 0x67, 0x03, 0x4e, 0x2a, 0x86, 0xe2, + 0x1c, 0x78, 0xd4, 0xb0, 0xfd, 0x99, 0x35, 0x51, + 0x96, 0xf2, 0x5e, 0x3a, 0x77, 0x13, 0xbf, 0xdb, + 0x25, 0x41, 0xed, 0x89, 0xc4, 0xa0, 0x0c, 0x68, + 0x81, 0xe5, 0x49, 0x2d, 0x60, 0x04, 0xa8, 0xcc, + 0x32, 0x56, 0xfa, 0x9e, 0xd3, 0xb7, 0x1b, 0x7f, + 0xe4, 0x80, 0x2c, 0x48, 0x05, 0x61, 0xcd, 0xa9, + 0x57, 0x33, 0x9f, 0xfb, 0xb6, 0xd2, 0x7e, 0x1a, + 0xf3, 0x97, 0x3b, 0x5f, 0x12, 0x76, 0xda, 0xbe, + 0x40, 0x24, 0x88, 0xec, 0xa1, 0xc5, 0x69, 0x0d, + 0xca, 0xae, 0x02, 0x66, 0x2b, 0x4f, 0xe3, 0x87, + 0x79, 0x1d, 0xb1, 0xd5, 0x98, 0xfc, 0x50, 0x34, + 0xdd, 0xb9, 0x15, 0x71, 0x3c, 0x58, 0xf4, 0x90, + 0x6e, 0x0a, 0xa6, 0xc2, 0x8f, 0xeb, 0x47, 0x23, + ]) + } + + func testLookupTableICODE() { + verifyLookupTable(for: .iCode, equalsTo: [ + 0x00, 0x1d, 0x3a, 0x27, 0x74, 0x69, 0x4e, 0x53, + 0xe8, 0xf5, 0xd2, 0xcf, 0x9c, 0x81, 0xa6, 0xbb, + 0xcd, 0xd0, 0xf7, 0xea, 0xb9, 0xa4, 0x83, 0x9e, + 0x25, 0x38, 0x1f, 0x02, 0x51, 0x4c, 0x6b, 0x76, + 0x87, 0x9a, 0xbd, 0xa0, 0xf3, 0xee, 0xc9, 0xd4, + 0x6f, 0x72, 0x55, 0x48, 0x1b, 0x06, 0x21, 0x3c, + 0x4a, 0x57, 0x70, 0x6d, 0x3e, 0x23, 0x04, 0x19, + 0xa2, 0xbf, 0x98, 0x85, 0xd6, 0xcb, 0xec, 0xf1, + 0x13, 0x0e, 0x29, 0x34, 0x67, 0x7a, 0x5d, 0x40, + 0xfb, 0xe6, 0xc1, 0xdc, 0x8f, 0x92, 0xb5, 0xa8, + 0xde, 0xc3, 0xe4, 0xf9, 0xaa, 0xb7, 0x90, 0x8d, + 0x36, 0x2b, 0x0c, 0x11, 0x42, 0x5f, 0x78, 0x65, + 0x94, 0x89, 0xae, 0xb3, 0xe0, 0xfd, 0xda, 0xc7, + 0x7c, 0x61, 0x46, 0x5b, 0x08, 0x15, 0x32, 0x2f, + 0x59, 0x44, 0x63, 0x7e, 0x2d, 0x30, 0x17, 0x0a, + 0xb1, 0xac, 0x8b, 0x96, 0xc5, 0xd8, 0xff, 0xe2, + 0x26, 0x3b, 0x1c, 0x01, 0x52, 0x4f, 0x68, 0x75, + 0xce, 0xd3, 0xf4, 0xe9, 0xba, 0xa7, 0x80, 0x9d, + 0xeb, 0xf6, 0xd1, 0xcc, 0x9f, 0x82, 0xa5, 0xb8, + 0x03, 0x1e, 0x39, 0x24, 0x77, 0x6a, 0x4d, 0x50, + 0xa1, 0xbc, 0x9b, 0x86, 0xd5, 0xc8, 0xef, 0xf2, + 0x49, 0x54, 0x73, 0x6e, 0x3d, 0x20, 0x07, 0x1a, + 0x6c, 0x71, 0x56, 0x4b, 0x18, 0x05, 0x22, 0x3f, + 0x84, 0x99, 0xbe, 0xa3, 0xf0, 0xed, 0xca, 0xd7, + 0x35, 0x28, 0x0f, 0x12, 0x41, 0x5c, 0x7b, 0x66, + 0xdd, 0xc0, 0xe7, 0xfa, 0xa9, 0xb4, 0x93, 0x8e, + 0xf8, 0xe5, 0xc2, 0xdf, 0x8c, 0x91, 0xb6, 0xab, + 0x10, 0x0d, 0x2a, 0x37, 0x64, 0x79, 0x5e, 0x43, + 0xb2, 0xaf, 0x88, 0x95, 0xc6, 0xdb, 0xfc, 0xe1, + 0x5a, 0x47, 0x60, 0x7d, 0x2e, 0x33, 0x14, 0x09, + 0x7f, 0x62, 0x45, 0x58, 0x0b, 0x16, 0x31, 0x2c, + 0x97, 0x8a, 0xad, 0xb0, 0xe3, 0xfe, 0xd9, 0xc4, + ]) + } + + func testLookupTableITU() { + verifyLookupTable(for: .itu, equalsTo: [ + 0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15, + 0x38, 0x3f, 0x36, 0x31, 0x24, 0x23, 0x2a, 0x2d, + 0x70, 0x77, 0x7e, 0x79, 0x6c, 0x6b, 0x62, 0x65, + 0x48, 0x4f, 0x46, 0x41, 0x54, 0x53, 0x5a, 0x5d, + 0xe0, 0xe7, 0xee, 0xe9, 0xfc, 0xfb, 0xf2, 0xf5, + 0xd8, 0xdf, 0xd6, 0xd1, 0xc4, 0xc3, 0xca, 0xcd, + 0x90, 0x97, 0x9e, 0x99, 0x8c, 0x8b, 0x82, 0x85, + 0xa8, 0xaf, 0xa6, 0xa1, 0xb4, 0xb3, 0xba, 0xbd, + 0xc7, 0xc0, 0xc9, 0xce, 0xdb, 0xdc, 0xd5, 0xd2, + 0xff, 0xf8, 0xf1, 0xf6, 0xe3, 0xe4, 0xed, 0xea, + 0xb7, 0xb0, 0xb9, 0xbe, 0xab, 0xac, 0xa5, 0xa2, + 0x8f, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9d, 0x9a, + 0x27, 0x20, 0x29, 0x2e, 0x3b, 0x3c, 0x35, 0x32, + 0x1f, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0d, 0x0a, + 0x57, 0x50, 0x59, 0x5e, 0x4b, 0x4c, 0x45, 0x42, + 0x6f, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7d, 0x7a, + 0x89, 0x8e, 0x87, 0x80, 0x95, 0x92, 0x9b, 0x9c, + 0xb1, 0xb6, 0xbf, 0xb8, 0xad, 0xaa, 0xa3, 0xa4, + 0xf9, 0xfe, 0xf7, 0xf0, 0xe5, 0xe2, 0xeb, 0xec, + 0xc1, 0xc6, 0xcf, 0xc8, 0xdd, 0xda, 0xd3, 0xd4, + 0x69, 0x6e, 0x67, 0x60, 0x75, 0x72, 0x7b, 0x7c, + 0x51, 0x56, 0x5f, 0x58, 0x4d, 0x4a, 0x43, 0x44, + 0x19, 0x1e, 0x17, 0x10, 0x05, 0x02, 0x0b, 0x0c, + 0x21, 0x26, 0x2f, 0x28, 0x3d, 0x3a, 0x33, 0x34, + 0x4e, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5c, 0x5b, + 0x76, 0x71, 0x78, 0x7f, 0x6a, 0x6d, 0x64, 0x63, + 0x3e, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2c, 0x2b, + 0x06, 0x01, 0x08, 0x0f, 0x1a, 0x1d, 0x14, 0x13, + 0xae, 0xa9, 0xa0, 0xa7, 0xb2, 0xb5, 0xbc, 0xbb, + 0x96, 0x91, 0x98, 0x9f, 0x8a, 0x8d, 0x84, 0x83, + 0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc, 0xcb, + 0xe6, 0xe1, 0xe8, 0xef, 0xfa, 0xfd, 0xf4, 0xf3, + ]) + } + + func testLookupTableMaxim() { + verifyLookupTable(for: .maxim, equalsTo: [ + 0x00, 0x5e, 0xbc, 0xe2, 0x61, 0x3f, 0xdd, 0x83, + 0xc2, 0x9c, 0x7e, 0x20, 0xa3, 0xfd, 0x1f, 0x41, + 0x9d, 0xc3, 0x21, 0x7f, 0xfc, 0xa2, 0x40, 0x1e, + 0x5f, 0x01, 0xe3, 0xbd, 0x3e, 0x60, 0x82, 0xdc, + 0x23, 0x7d, 0x9f, 0xc1, 0x42, 0x1c, 0xfe, 0xa0, + 0xe1, 0xbf, 0x5d, 0x03, 0x80, 0xde, 0x3c, 0x62, + 0xbe, 0xe0, 0x02, 0x5c, 0xdf, 0x81, 0x63, 0x3d, + 0x7c, 0x22, 0xc0, 0x9e, 0x1d, 0x43, 0xa1, 0xff, + 0x46, 0x18, 0xfa, 0xa4, 0x27, 0x79, 0x9b, 0xc5, + 0x84, 0xda, 0x38, 0x66, 0xe5, 0xbb, 0x59, 0x07, + 0xdb, 0x85, 0x67, 0x39, 0xba, 0xe4, 0x06, 0x58, + 0x19, 0x47, 0xa5, 0xfb, 0x78, 0x26, 0xc4, 0x9a, + 0x65, 0x3b, 0xd9, 0x87, 0x04, 0x5a, 0xb8, 0xe6, + 0xa7, 0xf9, 0x1b, 0x45, 0xc6, 0x98, 0x7a, 0x24, + 0xf8, 0xa6, 0x44, 0x1a, 0x99, 0xc7, 0x25, 0x7b, + 0x3a, 0x64, 0x86, 0xd8, 0x5b, 0x05, 0xe7, 0xb9, + 0x8c, 0xd2, 0x30, 0x6e, 0xed, 0xb3, 0x51, 0x0f, + 0x4e, 0x10, 0xf2, 0xac, 0x2f, 0x71, 0x93, 0xcd, + 0x11, 0x4f, 0xad, 0xf3, 0x70, 0x2e, 0xcc, 0x92, + 0xd3, 0x8d, 0x6f, 0x31, 0xb2, 0xec, 0x0e, 0x50, + 0xaf, 0xf1, 0x13, 0x4d, 0xce, 0x90, 0x72, 0x2c, + 0x6d, 0x33, 0xd1, 0x8f, 0x0c, 0x52, 0xb0, 0xee, + 0x32, 0x6c, 0x8e, 0xd0, 0x53, 0x0d, 0xef, 0xb1, + 0xf0, 0xae, 0x4c, 0x12, 0x91, 0xcf, 0x2d, 0x73, + 0xca, 0x94, 0x76, 0x28, 0xab, 0xf5, 0x17, 0x49, + 0x08, 0x56, 0xb4, 0xea, 0x69, 0x37, 0xd5, 0x8b, + 0x57, 0x09, 0xeb, 0xb5, 0x36, 0x68, 0x8a, 0xd4, + 0x95, 0xcb, 0x29, 0x77, 0xf4, 0xaa, 0x48, 0x16, + 0xe9, 0xb7, 0x55, 0x0b, 0x88, 0xd6, 0x34, 0x6a, + 0x2b, 0x75, 0x97, 0xc9, 0x4a, 0x14, 0xf6, 0xa8, + 0x74, 0x2a, 0xc8, 0x96, 0x15, 0x4b, 0xa9, 0xf7, + 0xb6, 0xe8, 0x0a, 0x54, 0xd7, 0x89, 0x6b, 0x35, + ]) + } + + func testLookupTableROHC() { + verifyLookupTable(for: .rohc, equalsTo: [ + 0x00, 0x91, 0xe3, 0x72, 0x07, 0x96, 0xe4, 0x75, + 0x0e, 0x9f, 0xed, 0x7c, 0x09, 0x98, 0xea, 0x7b, + 0x1c, 0x8d, 0xff, 0x6e, 0x1b, 0x8a, 0xf8, 0x69, + 0x12, 0x83, 0xf1, 0x60, 0x15, 0x84, 0xf6, 0x67, + 0x38, 0xa9, 0xdb, 0x4a, 0x3f, 0xae, 0xdc, 0x4d, + 0x36, 0xa7, 0xd5, 0x44, 0x31, 0xa0, 0xd2, 0x43, + 0x24, 0xb5, 0xc7, 0x56, 0x23, 0xb2, 0xc0, 0x51, + 0x2a, 0xbb, 0xc9, 0x58, 0x2d, 0xbc, 0xce, 0x5f, + 0x70, 0xe1, 0x93, 0x02, 0x77, 0xe6, 0x94, 0x05, + 0x7e, 0xef, 0x9d, 0x0c, 0x79, 0xe8, 0x9a, 0x0b, + 0x6c, 0xfd, 0x8f, 0x1e, 0x6b, 0xfa, 0x88, 0x19, + 0x62, 0xf3, 0x81, 0x10, 0x65, 0xf4, 0x86, 0x17, + 0x48, 0xd9, 0xab, 0x3a, 0x4f, 0xde, 0xac, 0x3d, + 0x46, 0xd7, 0xa5, 0x34, 0x41, 0xd0, 0xa2, 0x33, + 0x54, 0xc5, 0xb7, 0x26, 0x53, 0xc2, 0xb0, 0x21, + 0x5a, 0xcb, 0xb9, 0x28, 0x5d, 0xcc, 0xbe, 0x2f, + 0xe0, 0x71, 0x03, 0x92, 0xe7, 0x76, 0x04, 0x95, + 0xee, 0x7f, 0x0d, 0x9c, 0xe9, 0x78, 0x0a, 0x9b, + 0xfc, 0x6d, 0x1f, 0x8e, 0xfb, 0x6a, 0x18, 0x89, + 0xf2, 0x63, 0x11, 0x80, 0xf5, 0x64, 0x16, 0x87, + 0xd8, 0x49, 0x3b, 0xaa, 0xdf, 0x4e, 0x3c, 0xad, + 0xd6, 0x47, 0x35, 0xa4, 0xd1, 0x40, 0x32, 0xa3, + 0xc4, 0x55, 0x27, 0xb6, 0xc3, 0x52, 0x20, 0xb1, + 0xca, 0x5b, 0x29, 0xb8, 0xcd, 0x5c, 0x2e, 0xbf, + 0x90, 0x01, 0x73, 0xe2, 0x97, 0x06, 0x74, 0xe5, + 0x9e, 0x0f, 0x7d, 0xec, 0x99, 0x08, 0x7a, 0xeb, + 0x8c, 0x1d, 0x6f, 0xfe, 0x8b, 0x1a, 0x68, 0xf9, + 0x82, 0x13, 0x61, 0xf0, 0x85, 0x14, 0x66, 0xf7, + 0xa8, 0x39, 0x4b, 0xda, 0xaf, 0x3e, 0x4c, 0xdd, + 0xa6, 0x37, 0x45, 0xd4, 0xa1, 0x30, 0x42, 0xd3, + 0xb4, 0x25, 0x57, 0xc6, 0xb3, 0x22, 0x50, 0xc1, + 0xba, 0x2b, 0x59, 0xc8, 0xbd, 0x2c, 0x5e, 0xcf, + ]) + } + + func testLookupTableWCDMA() { + verifyLookupTable(for: .wcdma, equalsTo: [ + 0x00, 0xd0, 0x13, 0xc3, 0x26, 0xf6, 0x35, 0xe5, + 0x4c, 0x9c, 0x5f, 0x8f, 0x6a, 0xba, 0x79, 0xa9, + 0x98, 0x48, 0x8b, 0x5b, 0xbe, 0x6e, 0xad, 0x7d, + 0xd4, 0x04, 0xc7, 0x17, 0xf2, 0x22, 0xe1, 0x31, + 0x83, 0x53, 0x90, 0x40, 0xa5, 0x75, 0xb6, 0x66, + 0xcf, 0x1f, 0xdc, 0x0c, 0xe9, 0x39, 0xfa, 0x2a, + 0x1b, 0xcb, 0x08, 0xd8, 0x3d, 0xed, 0x2e, 0xfe, + 0x57, 0x87, 0x44, 0x94, 0x71, 0xa1, 0x62, 0xb2, + 0xb5, 0x65, 0xa6, 0x76, 0x93, 0x43, 0x80, 0x50, + 0xf9, 0x29, 0xea, 0x3a, 0xdf, 0x0f, 0xcc, 0x1c, + 0x2d, 0xfd, 0x3e, 0xee, 0x0b, 0xdb, 0x18, 0xc8, + 0x61, 0xb1, 0x72, 0xa2, 0x47, 0x97, 0x54, 0x84, + 0x36, 0xe6, 0x25, 0xf5, 0x10, 0xc0, 0x03, 0xd3, + 0x7a, 0xaa, 0x69, 0xb9, 0x5c, 0x8c, 0x4f, 0x9f, + 0xae, 0x7e, 0xbd, 0x6d, 0x88, 0x58, 0x9b, 0x4b, + 0xe2, 0x32, 0xf1, 0x21, 0xc4, 0x14, 0xd7, 0x07, + 0xd9, 0x09, 0xca, 0x1a, 0xff, 0x2f, 0xec, 0x3c, + 0x95, 0x45, 0x86, 0x56, 0xb3, 0x63, 0xa0, 0x70, + 0x41, 0x91, 0x52, 0x82, 0x67, 0xb7, 0x74, 0xa4, + 0x0d, 0xdd, 0x1e, 0xce, 0x2b, 0xfb, 0x38, 0xe8, + 0x5a, 0x8a, 0x49, 0x99, 0x7c, 0xac, 0x6f, 0xbf, + 0x16, 0xc6, 0x05, 0xd5, 0x30, 0xe0, 0x23, 0xf3, + 0xc2, 0x12, 0xd1, 0x01, 0xe4, 0x34, 0xf7, 0x27, + 0x8e, 0x5e, 0x9d, 0x4d, 0xa8, 0x78, 0xbb, 0x6b, + 0x6c, 0xbc, 0x7f, 0xaf, 0x4a, 0x9a, 0x59, 0x89, + 0x20, 0xf0, 0x33, 0xe3, 0x06, 0xd6, 0x15, 0xc5, + 0xf4, 0x24, 0xe7, 0x37, 0xd2, 0x02, 0xc1, 0x11, + 0xb8, 0x68, 0xab, 0x7b, 0x9e, 0x4e, 0x8d, 0x5d, + 0xef, 0x3f, 0xfc, 0x2c, 0xc9, 0x19, 0xda, 0x0a, + 0xa3, 0x73, 0xb0, 0x60, 0x85, 0x55, 0x96, 0x46, + 0x77, 0xa7, 0x64, 0xb4, 0x51, 0x81, 0x42, 0x92, + 0x3b, 0xeb, 0x28, 0xf8, 0x1d, 0xcd, 0x0e, 0xde, + ]) + } + +} diff --git a/Tests/CRCTestCase.swift b/Tests/CRCTestCase.swift new file mode 100644 index 0000000..58e288f --- /dev/null +++ b/Tests/CRCTestCase.swift @@ -0,0 +1,101 @@ +// +// CRCTestCase.swift +// +// Copyright © 2020 QuickBird Studios. All rights reserved. +// + +import XCTest +@testable import CRC + +class CRCTestCase: XCTestCase { + + func printLookupTable(for crc: CRC) { + let lookupTable = crc.lookupTable + print("[") + for row in 0..<32 { + let string = "\t" + + lookupTable[(row * 8)..<((row + 1) * 8)] + .map { "0x\($0.hex)" } + .joined(separator: ", ") + + "," + + print(string) + } + print("]") + } + + func verifyCalculator(for inputData: Data, with crcs: [CRC]) { + var calculator: CRCCalculator! + for crc in crcs { + let expectedResult = crc.calculate(for: inputData) + calculator?.reset(switchingTo: crc) + calculator = calculator ?? CRCCalculator(crc) + calculator.append(inputData) + XCTAssertNoThrow(try calculator.verify(expectedResult)) + let actualResult = calculator.finalValue + guard expectedResult == actualResult else { continue } + + for _ in 1..<100 { + var wrongResult = expectedResult + while wrongResult == expectedResult { + wrongResult = Value.random(in: Value.min...Value.max) + } + XCTAssertThrowsError(try calculator.verify(wrongResult)) { error in + switch error { + case let error as VerificationError: + XCTAssertEqual(error.expectedValue, wrongResult) + XCTAssertEqual(error.actualValue, expectedResult) + + let prefix = "VerificationError<" + String(describing: Value.self) + ">" + let expectedString = "expected: 0x" + wrongResult.hex + let actualString = "actual: 0x" + actualResult.hex + XCTAssertEqual( + String(describing: error), + prefix + "(" + expectedString + ", " + actualString + ")" + ) + default: + XCTFail("Unexpected error: \(error)") + } + } + } + } + } + + func verifyLookupTable(for crc: CRC, equalsTo lookupTable: [Value]) { + XCTAssertEqual(crc.lookupTable, lookupTable) + } + + func verify(for inputData: Data, expected expectedResults: [(Value, CRC)]) { + for (expectedResult, crc) in expectedResults { + let actualResult = crc.calculate(for: inputData) + XCTAssertEqual(actualResult, expectedResult) + guard actualResult == expectedResult else { continue } + + XCTAssertNoThrow(try crc.verify(expectedResult, for: inputData)) + for _ in 1..<100 { + var wrongResult = expectedResult + while wrongResult == expectedResult { + wrongResult = Value.random(in: Value.min...Value.max) + } + XCTAssertThrowsError(try crc.verify(wrongResult, for: inputData)) { error in + switch error { + case let error as VerificationError: + XCTAssertEqual(error.expectedValue, wrongResult) + XCTAssertEqual(error.actualValue, expectedResult) + + let prefix = "VerificationError<" + String(describing: Value.self) + ">" + let expectedString = "expected: 0x" + wrongResult.hex + let actualString = "actual: 0x" + actualResult.hex + XCTAssertEqual( + String(describing: error), + prefix + "(" + expectedString + ", " + actualString + ")" + ) + default: + XCTFail("Unexpected error: \(error)") + } + } + } + } + } + +} From ed0e528326181d760ccefbbd2920022e57314f87 Mon Sep 17 00:00:00 2001 From: Paul Kraft Date: Thu, 20 Jul 2023 14:41:49 +0200 Subject: [PATCH 2/4] CRC: Merge refIn and refOut into one property --- .../UserInterfaceState.xcuserstate | Bin 52016 -> 52460 bytes Sources/CRC.swift | 15 +++++------- Sources/CRC16.swift | 22 +++++++++--------- Sources/CRC32.swift | 8 +++---- Sources/CRC64.swift | 4 ++-- Sources/CRC8.swift | 10 ++++---- 6 files changed, 28 insertions(+), 31 deletions(-) diff --git a/.swiftpm/xcode/package.xcworkspace/xcuserdata/pauljohanneskraft.xcuserdatad/UserInterfaceState.xcuserstate b/.swiftpm/xcode/package.xcworkspace/xcuserdata/pauljohanneskraft.xcuserdatad/UserInterfaceState.xcuserstate index 803276ee5aab32a236c594d7f43fd9fba92111c1..da5a1ea623a98101c7a4112609934a9ebb66a4b6 100644 GIT binary patch delta 21893 zcmaf*1wa((-}rZGcc&Im5owT+kdP2WkdTm&kOlz(Q9(kw-FX0uu$B-5S;D|>J-hq# z>^!^sJiW93&#>&>{oeb%@87){cAt6XndkGZC+2x>V>9-$6`P-oBriz$AYF=dAf3n> zWG%7|*@$dHb|F6@7m$m{CFC-41-Xh`L#`t?kekRYY{q6K5Bp(qJvQ*)EG5EO;HPU7;1;wqYkJeIudn7y-^?37Y#;3(8=f&G#$-A zr=po?mK4oKbI@sME?S6Ipq1!!v<97lHlTCSd1wo|2;GQoLN}vZ(5>h;bUV5O-HGl( ze?s@6N6};Gar7+uGkOKRie5vnqc_m|=mYc%`W5|#en)>`0t~@W48w4Yz(`CLQ^Pc{ zL6`w%hz-UpFiUJS=8gGaQeVsu8-w{{0azdwgpI|*uox^BOTs2#Q?PU_1Ixqmu{x|C zYry7W^RW5Y0&F2B!y2(BtQBj=AbcX8hEKvL<5Tc-JOiJKXX06SHlBx<;$=981AGo%i`U`xcmv*qH{Y_)dHeei%QApTaNT7x7E@E&MkA0sn|g|G@vmKjEM8FZfsd z8~z>tL0|+$(1aS%kI*8t2^~V0&?8KVA%r{OL3k2g#Aw2s@F9E&KVl5wPmCoZh&Upi zNF^o`nM4*bgP2LoB4!hFh+3kKs3#hTxx_p|Ml2@U2|2Nv=poh+TZpa18R9JQGjUEz zoF{%EE)W-qOT=a33UPzDM?4{(5^srj#BaoB;)}4qaDY%Ka3Y~=`gf2oa;b>vJaJ(=@~D~c3FiK0bGq6wlBQK_g*R4%FzRf?vIq$18$1VmM$nW6^KTv4N_NwiGV zCR#3P7s*AdMLnWJqQjyiqNAc?qT`|yqLZRiqSK-?qVuAwqHCgGMR#Nj5h9%;P8a8h zr-@6%rQ$MimAG15C!QysFK!e!i8qKhiZ_Wji?@ikinocki+6~3ig$^B67Lfq6`vNL z5nmEt7GDux72grx6@M0g5q}kb6Mq-~AO$2sq9jJ*Btep-Dyc?lkb_7A(vTcXT9B5c zBRPU}AxDw!Ds_#zMct(y zP>-o+)H~`o>OJ+5`b7Pp1vEly(1U1AT8q}Eb!c5$kJhIRWS@n!)ReZP?P&+vkseMv z(a!V;+MV{N1L#0Hh#pHv(=qgTdICL-&ZYC{e7b-NqYLR0x|FV+_&{yee^mY0MeUpAczocK$ujx1RTlyXSjs8ym zkTL=WVF*UZFbvD6G5r_~MxQZY3>hoNnz3PQnPH3_W6!uVzKlOJmI-D;m~bY7nZ!(H zrZDMD1~Zk(WU`oSrhqAA%9#qLl9|rbFtyBlW&yL1X=9c%?Tno1U^ICFU}7lext_WF9e(S(L?CoF!NxD`Leg$xC9ms04Cafttgf(N$Sqs*Ib!3OLPV7k5mGxkQ*s*LR8_$ksC$JOQDQr5M z#b&d4Y(C4eGuSz7EjyQ8$TmvZCRWaNu$^od+s$rbH?v#Vt?V{-H@k;D$ew1;uxHt; z>^1f}dxyQtK4gDqKd>L!KiEInPwZ#*i-eE}B_fGf!bo%^MiO(0mBd#gWVAHlBR2YKS0Cd}yD0(e2 zvYK1WZRSpJcexJ$p#Y)}5J!Ln03;b8g#f7s$Z~*e0myNH+yclOfT94^0H_r}y|=ir z9Sn*L*>X>_89`KJCE6`Wq)b&uhw`ux^!`%~mkrn1NS1LNSIQ-DV9PN!Bg{%||>_EDaP_B|o?m$){tGVf% zRJLDF%X&RBqMaLWq6MpkiBZo2GU_@F3cH*!p1*Msaq z_9FX`{m232AaV#fj2uCZay8rxZYDR2o6XJPYPmYDo@?kqjw6EwLy*D9Y2=K+2L3%K z7{bkkB&zUO$hGuRE$XH6LT)1?i%h%V$l@_;|M`P_ouW4x-WDy1ZT zj=bcFUvM%x@``KZiPhgBzw_1q4H7r;#2=7wu37djd4L77&S?Kz1+B7xugDJt>vzc7 z+JS^4AGlOLJ7h%(R28zKLR5r`Q4*z48f8!xm7prz5^gECjBDeTbM2g*>)<-Mt{zlP z!HTLYSW!*L+TF*xrjK=FFRL#)1hS%L+=@O{)Dp6yLs2W#8nxk8a;v!2To2SOt%|E^ zs}gWl+&ai>8i=}~9y~)R>dqx|>mdW`1sOJQX^9haQVX-vvI~OJ zvL_czQHv;7mg9#8^kSp_5PQ>Kw}AtqY-E%8ihuqF=#9r$8F)Za@)A= z+zxIhw~PCU+s*CiLC5!DPw2y*2(kC}VIS zMSO+OG@PZJn{kbAb)U|xhuWLcvXGX5z4BbKu__= zC%J2K^fY&!M;?ftLodMkqvxSn-+*R~UW8_SlQ(PGJ~MTVo9M3!y4#TM4o`Ox3Itx~ z?f4=3hNpXkK1QFQPtj-SbMyuJ5`Bff=I(L#xd+@s?h*Hxd%`{Co^j86(6@bbzxOHh zPe}KokM4D!Lf`k&d0;|Fhl#kCeRLQF=`dPg!ynu$=-&J>Ue&0N4eN&ufNWTQ?u{H% z=ic&cgD_1@r&pbrHdN<3SbIzl*8Vq{g{6*$5oX#;hM7RJ-~YY_$zrjgm=h$!tT1cL z2D8P6VRo23=72e3!?};#AKahZC+;)%h5O2VNzjlk)I|SP@o?m0+b<8CH%} zV3pW(fY1P80Kx)90uU8|r~*U{ApHQ+A0PvIFs@GwHGN{3&5J=@DTYBxG3fS*p_vy$ z3qS@c#juzc!xCf&e*i>-o7{VXVqlb2@4&ivF?0e%Q;u~5L`xxt)!15v7}oG&(B_HO z^J38Xw-{_nlx1zfwkyQ2jTeL7-#77M(8l&)$9XaA#r9$Qu>;sa>=1SsJAxg>j>(qU zYFh!syazkc2Yd$M_*Muz&jVX1fvpv-D?sdff&H;xdEh$$u~Y)z=Ybz!5BUQiLjeMd z<Um`#0>aDX@g#2FwX0OA6W zkpOW8h#Npg0mQur?`xEBbp<*O8zq2vDA7kN(Z}?n`{8`Mgqs1xvkx8T8z$@lZp9zH z&|Zo&M4!-CdE6d%gy6UXK)mHRtd38wws9BStykN)E3a)|$b`G|On(2?HaG=M}YMUf9hffpcd z`~i??4mvqJK|u^qR=ymslp2;hmKk1SFW!{+UO*E$hNMDw&!09h<2pnEJ)(2ggPc-jP>b}6LA&-1i- zkhZ^Uo});MNF$~wa3}M)ZU3oaZ6cc}<#BU}X+$oON8}R)L?KZ`6cZ(~=kB~YukInr z;6MR>i0OS`RXkV^1cM)dtW|<->I0k4gF*4EQGzx8pI}RfWjxqYfUJ`fZ2(!{YtBRm z(anQ(@?aZyHLgHb17sr{`uxw1wCY5qMXV(@C|K9?tefFjiCDo&;a$9HwTW%S0iJa` zv4hx2>>_?5b`yJuy~I9ZzbxB}XWiRF9PCr#(LUCbJnKHC5)UX@kM^-%Ha_6DSlM7;GNtPqZ;FZRI-2SZrYT4>B49MsMw#c8~% zMxRE67Q&$rSZE25D{>)}@KxC_zC$#J2_1NzP@z2^s;)sE;c%Ykx=hVaM{}fbR4=X2 zjiOxeo5>gDp7#B)ss$WtX(#{Z>6VXiQrXUYS}bGfhpATN5EN`&PKrZS%CC2xBg zyzTXd6)hnU)+nH=d8pU_d0AUnD{SJS>V);e2H{-cJmGxd0^vfTOxP&Jc{g zDQj_`vf6m4&q`%|?Nb&iP(ZEaq1FN9ixO(%{|U82xQmC{36O7cA#97j_d@Lx9#lXb z;Gur}XYkMx9v8xq5uBP3o`g^+d>f){a(ewucwTsuhx$c$L3mMkNqAX!MR-+sO?X{+ zL&gO`D3s|D-s;oT-9D&?5DI1cG=-`vq0|)?_!|%P9-tB>)JF&<{6k>F9{^4Sl=hxr zD?utP@ViLBgZ%)gnp}hcw4W?De269?62qE{gwW&A{?Ow@B#bWT05}t~I9OX#MbxjC zOQgngLBiD{66z8i0J$_%28oOymPk{iCDIn@h;&7IB7Kp8$WSyGpo0La2~aJ7Y6DaU zpt=Cn1E@Yg4FGD`BQjRNip&&dDH_Vd4pzdN_L(JW31K4;e~}BM6^#U_Q6H^n6r>fo zi#+%PpvC|-QJf*KSXI(TEb)_~{FivD zh8@Pe3_EXw2sks?YJO%$bxCW$7Criju-8KS8GwFYoV zhS~yj7(nd+Y7bBcfI0$nI6$3xL|J`;$Q9*@@{z%!LS7KgNl6TyC*Tr?k`u5!^rfV%Z6zFE}D6NQQv zL5oI5@kC2_B6ry)XciqJzR^KaMO{4a=zm=06~9Kbo#$OES|?gB+928}+9cX6+9KL2 z+6GV`fcgT|51>%&{s4ty4+LlsK*s_!xJR@@;ku&T3M&`w=Xpc=To)auwDRaa+Os_E z&j1Zo(*DBJUVyal0B9Ib3r~>NSxI|cbd#sO0nl){=oUaDdX;`x^guy-pQnw44k~&C z11%c$uSQf&_)=Naa}gXj@j`gX3nAw3n|P(m+M|32!8sPOh)0;HM3@B7sod=?-=j(p zQD293OJxj&P?bufuG+F7HUqI2r-)Pe1EA#qtx%jHhoNd*-{Zv@;!H>)hBh=^F3tj| zly4(L#JS>vUKDXYkHW!PiHmp?@NX2+ugbE@#nXFH#Facs_1`z~0m@NaBc3I&>k!Wn z&jjcUfX?a=&lb-CDEx0ZH}#^RPM{*F7c>awisy0y4m$PBB-J$8I~9M~+5RdrkMWvf znIe6*EO~rRX0sTM4AzKS#EZnO;>F@6;-%tc;x_Seal2R!&{}}j0kj^V4FH`B(0Krb zmbn0+&@yEJZCoRUg9iR1UWstx)%>tnyp|VnlhP|%I1Zpoq1K^WER!AdyC9P!c6spA zS>inaZSFG_F+ZR6zm6Tm$HXUi;T{L*BDwe^KwEj?YKhN^&ntv`ju-A?X!qg^yjLud z*(I51UK2yxf(9YJ!AlW#A^*AxrKl^uCw|3q-xog+KNLR_KNdd`KNUX{KNr6czm%;> z(slyqYJm2v5x-V=f%rG*1w(oX{}96~Ym`Q`9{Pc*0&ojNmA%tBFFQV=%a@(C7!bT3ZCHxs0l5wBv$$lh1vqkm?=mt5d4$zIV+{_^wnj}B9MQZU; za1)Gzq%Q1fp_^e(OHb2?R7`D=aB2&nTcNR#y1a$KtKoxO$)TjJz^;?DBCSd2gWCbR z6QDnJlEX+l(jK5t1?K_!hLs8H3&i=&$h1#c|`+ za068}CFpK)FAoY;c~?$Cao^)XH4l+T`TB>FM|j`3&)5GrU;hU(&m2R|vt+O5q>|@& zy2t;x+DmtZyvNgBC9jd!$s6QN@)miU{FS^z-j!|2(KZF>yB_j>AKhcblza;5p7V6S zDe3;;CT)3}lYj*N$wPet=zAs9S03sc`JMbm2>|*#KtJ@JKSCA0w*k|b0R6pM7zsNRa_8+46Ra=c!Q5G?X((Y9vrNv`@ z|3_YkDYMTzimiryr!RR2g;W^)jFTP8AL5{j0F1sMSSXND5maP+aJYZ=#I%yobu)&?wQfe91 zCTlNhvgo3E1a{q2H?@LVNv)z*1I!p;CIB-9*bso3byI7owbVLlJ+(oWRGco_0V}hU z+9f+ztQEbR+5>Cqom`OCLG2baU!eGl`>0(;o<|+rR~}GL0GNd$@t`ts|70k^zQiNS z#66>)|CM+gmhDk8z~~fpPGHvst96DtOa0tiDO-RI0~ky^PyIq&pf1XaOG1h3)D7yU z>`aLlcANTDrdB#Y>o#>q&>RyS9$t`_o;~>jtP-E+KENCnmJMZ;zaRaN-%l04b(L24 zoPsS&2law_39u0WbLpU7Q*UH{mZpv3A%9m^{eb$RzpDO+BC);V?167EQCZSw>MQR8 zUjQ~rPJNRtDbx2xX+|(`HI30YP0&JGM2l&Xrf3>qo&fU#*l2)x1I!0tz5w$B*cgEM zuNDlUCCFe}l~$ws(f#QGTfUbKL5zmbL!p>xGuoWCpe+Fw2C#7e3kO(47i~pb(>AoN zY)r)p7Z-X|Cq0sOrQHA)3$R3hL1TvfjNaG9vJj4G*Tr{g(`A4;?{A!Vri-Cz-%aO%)iJpaO#nbgV#yj-%tZe5^FUGZN^;gy8V8 zg$2nenQ72ik~`@HI!Vy1Fr8#&9g^uO0=pHk4yp7+dNe(Wp4?lLRDex{l>t~9z$UGr z)9DO)DxC?>832PhrT{D*VDLNqGDTKdwMGinLl-GDu_?#06k5DRVnoiw_HaAs~ za~3_SHxqPyu8^h$ui z_>vE>0)Q0)tY`?piUC%#5}Ha6Jl4`Hq2X+REfmK0-mo%wjZ+0!`Idb(x`>EZ)K5@R z_h-1HYNG|?1fvDkf_y=-AYCv?P_V^r_Fgn;FAd+Stfu$T`{@JpLHZDVm_9-urH=uu z0$`N@zGK3q0OJ4#Ls%8SssUER8|z8>6n&aLL!YI8hV?klKXeAbE&%Kzz^(x7D!{Ju z6}lx0uG=vB7X5%%{%!hK`VM`UzDM5&*i3-U0@!ST%>h^~!0J}e59vqrWBLjGlzs-V zdVnngSP#JV0&E|^j>SlS?P( z+z`8kDoscHEaM!LGe zGKciz^Ur{}-PJk=(9{J_FFx6bhAG}^a_WMw-xxld0jyL-CQJ+n>YxJuS)?jVKn3o_xK*9`N-!aQ;D|B)vWlGxi_NJvcLa~kqF zSHhghshw0x{67m*MK7dHO6q;)s7={*<py{Iy1gSV@dB9 zc@8XV8WbO$8w(#~onM?jsX#V#VS;oAT(5E*IfMLyJVf3jUy<){5v&*;0GGfT!L<}V zaEWU;T-z`nu4QTdweaQtTDW@kCv-1*5d1OsJMk*B-=Z!`6w>WV8U*3b4f; zj1HpeG%#+=D49yra6K4gI>np-U@HK&>JrT0!FV!W%xFOa zvV`%Gr8b#4ck`FK`dU|J3~WuqN)#*sOkk3#y1%!NS8_q>6yNmhiD89ld8H9)d08Dy zknC`i8y3oh$;_J#u?}XOY)JFaF_BCHjB`vB6V1dhu}mBj&%hR74Zzj{Y#qSX18f7p zHUezZN+yvXxH8F13X_Tq2H0lUcZE@93&3^)Y?o|F^CPt!CYSf?X#m?QXJD+{CR@;= zqgKR}z-Z3ESh-!!KvC?F?Q5}&kuu=#yfB#k#HIDMPs|Jk4%n49z^JsF?*{fZpG+Oo zz+Zw9X^)~TZfZQVzKFE^g3-zOX-TTuGS5XCvaD9dLB=fN71PKxG0hB&CHnz(0AL3J zcBqSKWfsHu_XJ>v0d}M}`0eGUCaDgFHxFFcDwOS7v{dG?$lRuzfjzb^W(Bj7S;fHq z8jQrp0d@jlC%c$6%v$Ocg%0hdw|^r*slP-k;m==>>j{iJMjR(kvR4UV2=R? zh4*wV^MU!u{K5PQE&Vg|h55>SW4<##SZJTH*?0~x*e?9RTR&_HJ^}1Az*&Gx0DOOr z8*^L2mnR}>s%$@4Q&tUNFXU{0fW4Gm>(+78phtDEgIG;~y#g4lic7W*sLzA z$La(4x*vN3u(zG8p%;o8e(V_5pAEp@%HGPSs)_*i z72qVm8GwC(uRLWL9nMntqOY3`VMEz4b{rcHux|ht02~2025C$VvH z{uAMfvGhslX?c;o!zX}!hcCtf_9IEvCOtd7z-(GhW@&a#R(f)#3;!GbjY`feOmoRg zo0OTBT97u;r6eaWq_Dunyf+lE2`HN=Q|Z*lI@lx`+i4{2eHzs*uwh}R)0kJv4`mh7 zdJ}Q9H}UUauDqOqTETm8oLdF&i4IpZc*=`8ihG5MdsFjLt$G`R8XuwNZX_D%I{DS1X0yuyeos(IZl^tA|m6Dd1q}nen zd*Z(m)l#P<=Oshlym86dlhfcDyChZB%$(HZg7lnhpX}5e{uY>|xHl+0JFTxcscJvv zWB!q<`ajFdN#!&FE>_j#1pR;X{Zj}OuvJN_8s1S65osj_-pVz8eNXOWtJxa9-T2=! zB*`KR)OBIZW@oaq*x7N@;P6;6Y63V7a4JbPR5n4~OZK^QK)*V+J{~^DH$5}0cNEPw z$PBs$VDs4dGN&#pWPvQL%fSmShh0LAgCp<1R-&@a>=GEP*cNsX+sZBmxGKQa0NxMa z{kzzu>@xf6}Sm-BRQPJDwVaZ z(22MQM+NMCfSdf|(T~`du$Rj|W}mQ6*=Ou?_65LA0X_uaW&k$_xCOv1SFo?x*X$d3 zeh1q#d?vm6b+cB?34UW52QA*&hJ62DlBtZ963hKk*9iVNfikvh^!H ztt2EI!AK~8+i~NsNmz+Qq9Rchs7TZ#{UrS*10?E#28o7bkVI1uA<>rUtlB6Y1>o`= z7!B+J?g8NXoIwD0`;QPK(Us^aLJa>X7l1qb6<@g0-ocQ>7#YziF_D-`Ae1A(od6DB zoAkM*#6sbg!~eTWOC>f6pLYKL`}9T1501ip1oI>#1P#1%jN}Bp9wBj+xFxCfhnD(3 zy`e)giuZ;8b_u3VD@;+%OixvG7_AijXIUa`>-Bf!fzF>i4MyXMW+~~DeP9?!&hCqA z5^sqQj2N(s<1;b6ASZ7O92w-~mHHQ?Wpzk=W$#w&OUFQSkoW`Kiys$Cf}kG8N`jMA z2c;I~<-s8PuloQ#8sJI)Rd14Ul5oi&Hip+5z2Fv43kVRuU)uTWx^= z_xYFFCh%%YmZV5h0qzU%F#r$vTWymRYV-T=YLiS=XwCos(i+^w(;M6Wi`x2n2a*yA z9A5WGN+o5Ia!G}xQZij4m2eUusRH;|fCmFS1mK|n4+Ho(fQJJ-0^pGVkLr=sC?+u_ zvk_ASE-;tW!%0j$x^EH_kL4zDlL_9f6MCm;`%B=OMY&`Nz+?JmGbL@ZByDv~WktFr zaGktdvI5|7a>*)y$MaK`nv%5=eu0N%9h`K=$HPfyBm!B@O@uKB&O+Ktwn=vOPEtyC zz)4Cx5l&Jf5%B%y#DBdZQdsFe$$r_!b%U@D$pP8=b)%)maDR>y+?NwThLKTZ3>gQv z->*IYa(To+mHBO*U8Hl0i0*j=-uh!0e7~Hr9<4Yz<~vL$R8Y+lgVO-IdERn2&n=aN$)~kqA2B-{F8Kj~mRVi1Qtx~H}uQFHVmC9$8uPWbF z1*)m4(^T_R3sj3#Z>T;|eWvuc5wDS;aY*Bw#xEKdH7*Zw9ON~~dywy-F@rV?+B0b1paX*rX}W6q zYX)kL)eO;Guen?EyygYXOPW_SuW8=Uyruc8=3UMEnh!NUX@1fCrujpvg=k?~gqBE) z)S|UmEfuYyT7gZIzV=}gv1*U8bDt}{z#nNF9^CY@tCCv;BfoYDDN z=e*7Zol81bbgt>#(0QZtPUpSO2c183KIweX`KI$j7tzIZ3EjcEp1Ntevvk+!{-XOq zZ-Ab?UZ`HI-gv!4y$O2hdU<*UdPRCAdS!YQdeiml^ycc#*OTcr>9y!>mFgYTJEnI+ z@08v-yRr}*sP{zgt=>Dm_j+ITNqvdFs(wFx4Sh|0ZGBz+q532AgY`r8$LUAt zN9o7t$LWvPPt>2FpQ2x^U#efOU#TzE2m00eGxTTa&(W{bZ_w}2KdJx9K*hk`Al9JL zV5z}wgKGx&3?3RhHh60A&fv3w^sB*lLxCY`h#LwG#fIvJgABC{bq)0m4Gl*b1{#JM zjx&rfj5UlmOfXC`%r?w5EHj*CSZ_GjaK2%aVT)m_;S$3h!ySfa41YE}Z+OA*lHnD@ zYlb%rZyEk-c-QcQ;U9*d48ItDGyDNZu-IT?uxKzjm>z64*l+OE!3~2q4ZbQJ{KZJi zXoOLeQIb)L(L|$3Mma_$MrB47M$?Trqbj2sqnSptjcScrj20U$HCk>YH|jJxV06~# zg3%?TD@HesZX4Y(x@Yv(=)JMPm@pO@lg1KbRpWlf1B{J~ZH;}5{fzyM1C7TThZu($ zhZ{#4M;pf)XB$s5&ND7BE;24LmX;Y;7*99mjH`@mjOE4$j31f^O)N}8O$tn8CYw#p znOrluX>!}-j>%J#cP8&mKA8Mr^2y|j$v2Z9ri`hIsha5k(}AXgOdU+ z*-5k0W;e`kn>{vrYWBhGv)Na(@8*~}VJ;P!ljeiWP0U@)UCl?CdzgEfdz<^3k1-E0 z4>AunPc=_7pKP9PKGi(SJjXoOJm0*~yx6?dyxDx4`E~Oz7Wx)G7U>qVEmm3_u{djS z-r|DAC5zh@k1d{BJhymh@!I08#cvirEKy6`Qe;V5(w1hHj+QQ#u9l-LM_c+>`dRu* zEn_U>EvHy!S>{;gS{7NBSe98}j<=oHb#Oj#UWvgpe zkF1_sy|j8`^}E$at4~&6tSM^^>!H>*)^^s8*3Q-=tw&jVT6tQ?Ec8qO+?O59o+eF)B+icr>+d|tC z+e%xhZIx|}t<1LFcAM=^+ugSNY!BKVu{~~k%J!`7dE1M&Pi ztJtgA8`xXfd)fQgkFgK554I1pkFbxnkF!s(pI~2TUt(WoUtvGp9@tmg&#<3mUu$1) zKi7VZ{VA#aYX?;a2ZuO^=?=>r_BdR3xbN`D;i^#}>!Mj!PZaIPP>j z>v-PrqT?0E>yEb^?>OFfeB}7l@x^e#aBMg+Tr`{n!~k+I}eW@ zUOs%;@PosjIMGfPPX11loN}DNQv^w#M&XT%wIW}Q`>b({^Ijhs!LEuF2LZJq6$J)MJ{Q=KO{ zr#ojl=Q!s{oeP~yoXef3I|Jut=T_$>&dZ#aJ9jvDIj?YD<-Epuo%06gGtMtYsEimk zB639eh~*>pjkrDHvkT@TbRk`6mjN!iF8VHpE=DdUE<;=#T%257T-;ndT)bS8Tryp9 zUGiOuT*_T4T{xF2mjx~|mv)zKmz6F(E*o4nxomaW?jk+va>3<^%X61kE^l4lyL@!{ z>uiH!^o*)5skoZ@MC`Ca&JD zsji&s9M^i+d9Djw7rS=4u5exDy2f>#>ju|NuKQdMx*l;o?t04gjO#PkkFH-_zq<+C z2sg1C<;J*ayXi^YhPau#4R;&q=H}+%=Huq)7T^}-7VkF2tBo!m#bk92o)cX#)64|Wf8k8qE6k8>aIUg|EL>0akP*L}Wwllvm~ z#qLYp*SPO=-|N2L{gC@{_ml2t+<$hz?f%^ThX?9Gc!)h{4~d7G#{drv4=oQ}4?7P> z4=0Zi9wR+Qd3bnud3byHdH8z-dQ9<{<*~-&tj9Y~4bPFDah|1~&7R9WJ3PBRS9)&r z+~v93bFb%q&x4+aJkG2^dHo9>1lF|D||2q1cx0bh&x2dUo4mJrAM`%veZu>+_j&IN z-j}_vdO!Al?<4l1eI!0=J_CF-e6)OYeGGhzd`x{t`i%1N@bU8T_VM%a_X+eF>l5lT z&L_er*Jr-ZR-Y?ApM4E{y`{dXzE!@Sju$9+%wp7H(J_q^|I z-@CpKd>{Kh^L^nb_EY!M^3(Ct_cQi0^)vUg^mFlZ^9%3`@eA{d@Qd|}_e=Df;Fsf9 z;kUrA(XYjCvEMSkcE3))6@IJz*7|MmJK}fT@1);pzq5Yl{Vw=j^1I@9-A{Vc@3!CP zF`8rC#w3lY9-}S%m|IYt=K>vV&0h$3i z0r~-h155(U0xScp1BM0o2KWaA28@*kganKWhzN)ZhzW=fNC-#@s0dgRus`5lAQ5O8 z7!sHr*bvwgxFv9V;I6>kfky(*2A&K2CGcY4<-n_f4+EbBJ`a2q_%`sjAeA7UAj2S| zAk!erAgdtTAiE&Xpx~hJpva(@poE~Lpp>AALHR*kP*c#Npd~?VLGqxkpp`*ALDF?W z8-un4od`M|bT;T*&@Vxkg02Kz3%U_>JLpc(y`b-7b;o*+O&vRH?7FePjC~ud5j&>Nw*L+^$@2z?a#B=lM6$IwrqUqgR{p<#HKVVHH8ec13Y=P|xmBuxDW}!`_6w3;R9nW7wbL)W1M9hw;ji`@U9dRP!Wuzq1E;1&vB63OOPmxz6??yg|d>r{S@?GTT$ZwH9 zqR=QjN-B&JN2x~*iqekKi!zKdit>mW8#OK}A}Ts+d{kmoa#U(mUQ}UJRn)AgIZ^dd z3!-FE%~6Y@Rz_`&IvI5)>Ri-?sLN5;qHae08g(z~VbqhTuTejuk!UQMh!#iF(QLFz zbie2U(F3FHqsK)TMK6lp6Ma8M7-JIS9g`fB5tAj2nHG~5QyxNvOn68+WF{@*a#axWJ7IP!!cFg^lhcQoLp2hqb^CcFKRf`=MJ1AB=)*yCptV!&U z*x|9GV`F0DV-sVOV<*N=j?IY8ik%jlA6pb#7dtn0e(b{7#@LqF*4QPn%VOJOJ7T+H z560e&!{el;aRG7D;u_< fGc6ZdD_m$>iof_O5%U%Yz!pm^zbbxR{D%0=@mu2$$DfbC z9DgnTX8hgw2l0>NpT>WP|0DiW{MYdl$LEgEA741WWc(fJ_?HP-f-r$hU=mak`X#6* z3`)>W&`U5(FisemFe`kvq{^hKq?)8zNpq4GC3Pq5N!p)uDCua@iKNp>KPUZ? zbSdd-(v76sNxvukk@P9)OVYOqf(hsZe1dR-cmh2^GC_5M)r6o4(0ImIQ#EyX=0I3+$MB_%CoO3Kufyp+O}l9ck4 z%9Pra`jojT3(|(AjY{)K^GfrXd~x#K$@eEeocttXRz_pS>WsA+8!|R$Y|Gf0u{&d5 z#=(pu8OJkjW!%ZQmmz(S@hIbI#`BDq8Lu98GW>{uiW@=_y=H$%u%&D1KnPr)knOtUd=FH65ncbP2Gk0YEl({GKVCIp` zW0@y1uV&uLe3tn-^KIt)%s(?fXMW54ktNB}&a%z2&l;XJBFi<)JZ9U)|9M_tjw&OtlX@EtfH*atn#eNti@TovTkSn$TouS$g;BQv)5#w$o?h!QufvC z>)H3SUu3_|ewY1w_Q&i$v%h42%b{}E9MzouIRkSB#p4*wbB6oG}+T8WIr*p66-p;*~dq4L{?lWob%iPzw z-}2BrBClVbMxJJ#PM%?&QJ!g@S)Nm#cbH+Fs2~6ptzu>U`|1O!MuXT zf|i2C1xpK77py5*SFo|*e!-i9cLnbYJ{HCnPAbeQoK~1$SX5Y9$Q4!>&Mcf=*i^W_ z@Mz(s!rO&+3m+6dDtun}s_&0rtF2#PuOi7lB_l2ejbQdm+_QeIM1BAr!IThdT6zhq&_ijv(W=S!}aJScfws$QyBYFp}5 z>QU-n8dO?R3QB8AHxn^(55 zY&qq3)EFUnq*y({~@?2od~7*L^KVNu~!;ZZTV!neY| zBB&y=BBmm~BC#U5BDJETqNQSU#iNQB74IuPRD7=_D#ev_rKD1=Qm@ja(yY?5(z?>I z(z$YE<)})J%Jj;X%EOgMD=$=Duaw@Zyi<9<@>%7J%GZ_eD&JRro{mkYtF)?gt4ymL zszz3MRfSZIuS%*)sYV4G*t4~$GkXFB{ zepCIf`hE3>>OZPKRe!1eR{f&}sljT98c_{dL)Q$d8B$|WV^w2YV_!48W<-r^O<>K~ zn$VhYHIX$jHE}fwHAyvPHFIh<*W9l8F++RC_!%WLKy7vH%vxFPirUq+Yil>uZm!){ zyR&w8?Y`QBwU=tI)LyT>RePuQe(j@L>C@WhwXbU5)S-3ib>?-hb)j_$b@_EO>l*9i zb?fUk)orcYQTJ2b-ns*IXY0<_U97uOcfIab-JQC7^?3c@dXM^u`bqWm^{w?C_1*QW z>etk-uisJsQ~loh1NDdNkJjI+f7?Jd7&i=SuxqeyaBK)|NNAYQklHY*A-!R0!_0y)jKt&y#V%Y(Ma&dF}ep3C0LKFU7HzRG?y ziW{j$wo$dQf1`S%b>rB^*v9O}nT>UgU5)D-cQzhsJllA!@n++%jdvRFH9l;7()eeS zYLjM@UXx*yQIlztO_N=dLz7!mWK&#IUX!%8X_@n(j2+ZF<%8wdqGQ+DtTy zo9Sjrvs$x3vr)52^N?nXW~*k~X1ivG=F!b*&7gTv^P%QT%^zCW7OfWD7K0X}7Sk59 z7MB*kmVlPAEuk&pEs-sWElDj!E!8bETjsRXx6Er<(9+f-Z|Q1T+0xUpwq;k#o|gU6 zmP0K^TaLF}YsvRqZf)Jsx~uilQs1S?OS6~e zE-hGEytHg-#nP6g?MwGAJ+Sofvg~EW%W9U*S|+Vs*05~;vW3gGFWbNDz_P>3&MdpW z?AEe7%kD3Gxa@Ho-lo z%iB8Iy4zN@t!X>bcD(IW+u64BZ5P@uw_R(y+4gJOy|#yKPuiX>XO z`#YTL%F@&RX$1{C=Zg4m50dV zrCiO>P+d(>}={>+j+3_a_7^|FI}o##$Bde=3SOuR$arp+`D4CCUli`&F^aM>grnA z)zkH@TPW@B*R9cQ)IGF2x_f;0tnS9{mhRT>72O-UH+OIA-r4>CTC}&8sG=wUz^Q~r zV2mkU9)`?Pks>TAw5+huN-zYmFfn983?s0MO+^en2tv|L^r5>9XRW>WT4xOmTBby0 z)|4?RqLK_LrDa!9v=qVYL7%=q@wHm*R>118f>xK+ZH24}>mNix95^8!)7xif*Fj&XmnsKu0SWoV*)0kCmB;Q9kVeP z^DrL|V=Nyi-mYEn6XI7fkCds6j4Q7)`Gg;<< z$uYU6z_?7QDKq89Z7!P2#$&3@ed9GxOsAQnCFGp7V>^KQ=MeVomQxQLH& z2_NSQKEsvl<|@9;_xK@u8CWy3kNw=l%^c(|?&cou<9-i^_#+SUXCCISc7(mw&a%tw z8ryI8*?%NfQYBq7WRGM@j^s;$9FamPl42>BQ&J&k<-A;wdhv=95?lPzD37FB0@5S> l5|RNKk}onM-(}ht=3C`+`nJt4%<%AeqaAGvEpq|i{{Q-*+~oiO delta 21372 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 { // MARK: Stored Properties public let initialValue: Value - public let refIn: Bool - public let refOut: Bool + public let reflected: Bool public let xorOut: Value public let lookupTable: [Value] @@ -22,19 +21,17 @@ public struct CRC { public init( polynomial: Value, initialValue: Value = 0, - refIn: Bool = false, - refOut: Bool = false, + reflected: Bool = false, xorOut: Value = 0 ) { - self.initialValue = refIn ? initialValue.reversed : initialValue - self.refIn = refIn - self.refOut = refOut + self.initialValue = reflected ? initialValue.reversed : initialValue + self.reflected = reflected self.xorOut = xorOut let indices = UInt8.min...UInt8.max self.lookupTable = [Value](unsafeUninitializedCapacity: indices.count) { pointer, initializedCapacity in var result: Value = 0 - if refIn { + if reflected { let reversedPolynomial = polynomial.reversed for index in indices { result = Value(index).littleEndian @@ -65,7 +62,7 @@ public struct CRC { // MARK: Methods public func calculate>(for bytes: S, in value: inout Value) { - if refIn { + if reflected { for byte in bytes { let input = Value(byte).littleEndian let index = (input ^ value) & 0xFF diff --git a/Sources/CRC16.swift b/Sources/CRC16.swift index 16ae8bb..84e7d51 100644 --- a/Sources/CRC16.swift +++ b/Sources/CRC16.swift @@ -10,8 +10,8 @@ public typealias CRC16 = CRC extension CRC16 { - public static let a = Self(polynomial: 0x1021, initialValue: 0xC6C6, refIn: true, refOut: true) - public static let arc = Self(polynomial: 0x8005, refIn: true, refOut: true) + public static let a = Self(polynomial: 0x1021, initialValue: 0xC6C6, reflected: true) + public static let arc = Self(polynomial: 0x8005, reflected: true) public static let aug_ccitt = Self(polynomial: 0x1021, initialValue: 0x1D0F) public static let buyPass = Self(polynomial: 0x8005) public static let ccitt_false = Self(polynomial: 0x1021, initialValue: 0xFFFF) @@ -19,19 +19,19 @@ extension CRC16 { public static let dds110 = Self(polynomial: 0x8005, initialValue: 0x800D) public static let dectR = Self(polynomial: 0x0589, xorOut: 0x0001) public static let dectX = Self(polynomial: 0x0589) - public static let dnp = Self(polynomial: 0x3D65, refIn: true, refOut: true, xorOut: 0xFFFF) + public static let dnp = Self(polynomial: 0x3D65, reflected: true, xorOut: 0xFFFF) public static let en13757 = Self(polynomial: 0x3D65, xorOut: 0xFFFF) public static let genibus = Self(polynomial: 0x1021, initialValue: 0xFFFF, xorOut: 0xFFFF) - public static let kermit = Self(polynomial: 0x1021, refIn: true, refOut: true) - public static let maxim = Self(polynomial: 0x8005, refIn: true, refOut: true, xorOut: 0xFFFF) - public static let mcrf4xx = Self(polynomial: 0x1021, initialValue: 0xFFFF, refIn: true, refOut: true) - public static let modbus = Self(polynomial: 0x8005, initialValue: 0xFFFF, refIn: true, refOut: true) - public static let riello = Self(polynomial: 0x1021, initialValue: 0xB2AA, refIn: true, refOut: true) + public static let kermit = Self(polynomial: 0x1021, reflected: true) + public static let maxim = Self(polynomial: 0x8005, reflected: true, xorOut: 0xFFFF) + public static let mcrf4xx = Self(polynomial: 0x1021, initialValue: 0xFFFF, reflected: true) + public static let modbus = Self(polynomial: 0x8005, initialValue: 0xFFFF, reflected: true) + public static let riello = Self(polynomial: 0x1021, initialValue: 0xB2AA, reflected: true) public static let t10_dif = Self(polynomial: 0x8BB7) public static let teledisk = Self(polynomial: 0xA097) - public static let tms37157 = Self(polynomial: 0x1021, initialValue: 0x89EC, refIn: true, refOut: true) - public static let usb = Self(polynomial: 0x8005, initialValue: 0xFFFF, refIn: true, refOut: true, xorOut: 0xFFFF) - public static let x25 = Self(polynomial: 0x1021, initialValue: 0xFFFF, refIn: true, refOut: true, xorOut: 0xFFFF) + public static let tms37157 = Self(polynomial: 0x1021, initialValue: 0x89EC, reflected: true) + public static let usb = Self(polynomial: 0x8005, initialValue: 0xFFFF, reflected: true, xorOut: 0xFFFF) + public static let x25 = Self(polynomial: 0x1021, initialValue: 0xFFFF, reflected: true, xorOut: 0xFFFF) public static let xmodem = Self(polynomial: 0x1021) } diff --git a/Sources/CRC32.swift b/Sources/CRC32.swift index 7a52203..5f29080 100644 --- a/Sources/CRC32.swift +++ b/Sources/CRC32.swift @@ -10,16 +10,16 @@ public typealias CRC32 = CRC extension CRC32 { - public static let `default` = Self(polynomial: 0x04C11DB7, initialValue: 0xFFFFFFFF, refIn: true, refOut: true, xorOut: 0xFFFFFFFF) + public static let `default` = Self(polynomial: 0x04C11DB7, initialValue: 0xFFFFFFFF, reflected: true, xorOut: 0xFFFFFFFF) public static let bzip2 = Self(polynomial: 0x04C11DB7, initialValue: 0xFFFFFFFF, xorOut: 0xFFFFFFFF) - public static let jamCRC = Self(polynomial: 0x04C11DB7, initialValue: 0xFFFFFFFF, refIn: true, refOut: true) + public static let jamCRC = Self(polynomial: 0x04C11DB7, initialValue: 0xFFFFFFFF, reflected: true) public static let mpeg2 = Self(polynomial: 0x04C11DB7, initialValue: 0xFFFFFFFF) public static let posix = Self(polynomial: 0x04C11DB7, xorOut: 0xFFFFFFFF) public static let sata = Self(polynomial: 0x04C11DB7, initialValue: 0x52325032) public static let xfer = Self(polynomial: 0x000000AF) - public static let c = Self(polynomial: 0x1EDC6F41, initialValue: 0xFFFFFFFF, refIn: true, refOut: true, xorOut: 0xFFFFFFFF) - public static let d = Self(polynomial: 0xA833982B, initialValue: 0xFFFFFFFF, refIn: true, refOut: true, xorOut: 0xFFFFFFFF) + public static let c = Self(polynomial: 0x1EDC6F41, initialValue: 0xFFFFFFFF, reflected: true, xorOut: 0xFFFFFFFF) + public static let d = Self(polynomial: 0xA833982B, initialValue: 0xFFFFFFFF, reflected: true, xorOut: 0xFFFFFFFF) public static let q = Self(polynomial: 0x814141AB) } diff --git a/Sources/CRC64.swift b/Sources/CRC64.swift index a6d3a8d..57053f5 100644 --- a/Sources/CRC64.swift +++ b/Sources/CRC64.swift @@ -10,7 +10,7 @@ public typealias CRC64 = CRC extension CRC64 { - public static let ecma = Self(polynomial: 0x42F0E1EBA9EA3693, initialValue: 0xFFFFFFFFFFFFFFFF, refIn: true, refOut: true, xorOut: 0xFFFFFFFFFFFFFFFF) - public static let iso = Self(polynomial: 0x000000000000001B, initialValue: 0xFFFFFFFFFFFFFFFF, refIn: true, refOut: true, xorOut: 0xFFFFFFFFFFFFFFFF) + public static let ecma = Self(polynomial: 0x42F0E1EBA9EA3693, initialValue: 0xFFFFFFFFFFFFFFFF, reflected: true, xorOut: 0xFFFFFFFFFFFFFFFF) + public static let iso = Self(polynomial: 0x000000000000001B, initialValue: 0xFFFFFFFFFFFFFFFF, reflected: true, xorOut: 0xFFFFFFFFFFFFFFFF) } diff --git a/Sources/CRC8.swift b/Sources/CRC8.swift index ffb7a85..87c67e1 100644 --- a/Sources/CRC8.swift +++ b/Sources/CRC8.swift @@ -12,13 +12,13 @@ extension CRC8 { public static let `default` = Self(polynomial: 0x07) public static let cdma2000 = Self(polynomial: 0x9B, initialValue: 0xFF) - public static let darc = Self(polynomial: 0x39, refIn: true, refOut: true) + public static let darc = Self(polynomial: 0x39, reflected: true) public static let dvbS2 = Self(polynomial: 0xD5) - public static let ebu = Self(polynomial: 0x1D, initialValue: 0xFF, refIn: true, refOut: true) + public static let ebu = Self(polynomial: 0x1D, initialValue: 0xFF, reflected: true) public static let iCode = Self(polynomial: 0x1D, initialValue: 0xFD) public static let itu = Self(polynomial: 0x07, xorOut: 0x55) - public static let maxim = Self(polynomial: 0x31, refIn: true, refOut: true) - public static let rohc = Self(polynomial: 0x07, initialValue: 0xFF, refIn: true, refOut: true) - public static let wcdma = Self(polynomial: 0x9B, refIn: true, refOut: true) + public static let maxim = Self(polynomial: 0x31, reflected: true) + public static let rohc = Self(polynomial: 0x07, initialValue: 0xFF, reflected: true) + public static let wcdma = Self(polynomial: 0x9B, reflected: true) } From d4213f3ae869032f4a733dce00d7030c5cc31334 Mon Sep 17 00:00:00 2001 From: Paul Date: Wed, 26 Jul 2023 17:35:50 +0200 Subject: [PATCH 3/4] Make VerificationError init public --- Sources/CRC+Verify.swift | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Sources/CRC+Verify.swift b/Sources/CRC+Verify.swift index 95c1dd3..d0336b1 100644 --- a/Sources/CRC+Verify.swift +++ b/Sources/CRC+Verify.swift @@ -12,6 +12,11 @@ public struct VerificationError: Error, CustomStringCo public let actualValue: Value public let expectedValue: Value + public init(actual: Value, expected: Value) { + self.actualValue = actual + self.expectedValue = expected + } + public var description: String { "\(String(describing: Self.self))(expected: 0x\(expectedValue.hex), actual: 0x\(actualValue.hex))" } @@ -24,8 +29,8 @@ extension CRC { let actualValue = calculate(for: bytes) guard expectedValue == actualValue else { throw VerificationError( - actualValue: actualValue, - expectedValue: expectedValue + actual: actualValue, + expected: expectedValue ) } } @@ -38,8 +43,8 @@ extension CRCCalculator { let actualValue = finalValue guard expectedValue == actualValue else { throw VerificationError( - actualValue: actualValue, - expectedValue: expectedValue + actual: actualValue, + expected: expectedValue ) } } From 124a8c9bb853bfc7199012d8e486ec5ccd507f04 Mon Sep 17 00:00:00 2001 From: Paul Kraft Date: Wed, 26 Jul 2023 17:42:49 +0200 Subject: [PATCH 4/4] Add Checksum protocol and simplify CRC verification --- .../UserInterfaceState.xcuserstate | Bin 52460 -> 56209 bytes Sources/CRC+Verify.swift | 45 ++++++------------ Sources/CRC.swift | 2 +- Sources/CRC32.swift | 1 - Sources/Checksum.swift | 14 ++++++ Sources/Hex.swift | 26 ++++++++++ 6 files changed, 56 insertions(+), 32 deletions(-) create mode 100644 Sources/Checksum.swift create mode 100644 Sources/Hex.swift diff --git a/.swiftpm/xcode/package.xcworkspace/xcuserdata/pauljohanneskraft.xcuserdatad/UserInterfaceState.xcuserstate b/.swiftpm/xcode/package.xcworkspace/xcuserdata/pauljohanneskraft.xcuserdatad/UserInterfaceState.xcuserstate index da5a1ea623a98101c7a4112609934a9ebb66a4b6..7344f4648d75b6858fbfacc98c3dc1dd277dc351 100644 GIT binary patch literal 56209 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�~aoirp@lKB8{Wgvd**HFS0>|TkQ$36?i*Eoug zz+mfmgAcZkwkMI?YYThV@qtC+`<%pGM=4~N_|)+o2k|q<=Z-HNUpfvrzH)r+IOzDs z@h!toF#IILPci&7!_P4MEW^(+{5-=iF#KYZj7$L}1(muwJUwWEvsPJnpq zK@^<;qUd7yec5`~kxsGW=1KINX9!9BIKQW^)+#+c17=!+78X zjK=}SDICVB41a9H2$7zRVi8W`ABI0MAOHeifMSf@)APgy97PC-d{!@l3HEshQCuwg zEEG#QieGT3%1so%Y>y(fSE7nlqTfQXhNJk^(Ms7TSSP~b)h2P7xLjNzt`tubSBa;K ztHm?KGZ_Z2=^KVYL4L>Z_Y6Y_96Yd}7zPjQmnM;gQ9Rcgpv5&D#b0d{{|pb%1f4+f zIG}hnM-lA#-)t1G=P2GF-pD@;|IY9q);GYYdJ65{-Y9P7ID#$tSG~A};lDeG<1M23 z%+En_JIC=K7;nWp_#pjndm2+$*uw4=@3&~&0W=bPltOliN5tnijE{id+f(2#DgNd{i9y|hLOm6 z@jFJMI*8*>;;)u=`~`3%(VVQ`0Y?(k9>>cIlSZdo&uw_bFlSEWq$Zh8!pZD%l=5~7 z$r%k~I%TKgRGperceD+1FN+gHCXH?74If1TLL}80iz{(g_itBTr5{vz)_#N9RyR`qev!Gt$3f zJUT}@N1Hr4M{ynpz_{zo;iEMf*bYd~EE}n@&hZw61suZUqZP7?Om)uV6i#zacNRK} zoHLv=owJ;?opYRX8A)X%jgfRlG8oBZWH2K`7|CJ;E@oJhbAFh@MNY4CG1}!U-GoSHPcPgpw=TkcxtdJD`eIGA~$ z9i3~qc7=C39TFR|OI+vN#JRlQd4uyt=S|L=og19>&IV_rb0Z^T7=c>GF;c+Dct$2L zGLex?@bPcr_be+T*TyAT@l{SNCoM7-cFj&ADgpp~5&ETY?GFarA$r+r%$Z7SiS&Xde zAcON<3ps=HIfJKj28%g^s}I9qgpgrF=yO$A5SDWY&*Tsma|l--5yBeRN)DmlRqHy{ z6>tSzAy=JinQOTV3=FU#&SKR&co7Hxv{Bsdy2C>8c8=ouqZG1B+~?ZG zQQYCW-}Qj&LDxgBhg~~ekGLLnJ;umYj9ksgHH=)#$aRcd&&Umoz=hnz$jwcz$E`8h z^|Te`c0JEg+yE$=V{$_{%1t((K=C-B$lv_xdW(^I8^y!F`ql2`k6oW~2tQ$@vEBu- zo{b%Z@PO-}1>x5m!cD-_e|Qs#1pdqk+|q#(e@RYG;NPx)T>nZ)!V;0FBuEZP zWMms7O^n>a$gPZQXXG|UZfE2UM($+ft|rN4DMLxMl%eF|1m0~c!+ULI_`nGQk3E4> z91tjhKDsANpaidkIdarS>My~<>UwDaBlp!y5bW8}F#@GDDbplS%HRav&v`n!mmv+8 zVDS&wgwjczzy~`}B1f781WLJ5o|G?*k;Y2nqylNYG(iF<_+dtNGV%x`k1_%(aTgLsx4pYI@n%cPYSfh#zHFLWRTD4i*tWg*Bof-iNX$OY0BoWV8Hh0;aR#nL6xrP5{6 z<{8QH_gUPfMHWFI51Gx7!_Z#GHmt#MeoCd}XsoWZy3arj-E!H-Tb zcpMmP;taz0^tR35ZNQ*(J4)prM&5yZE&K}%LOUgibe{w>ZuQa*M&7HJ9$@7C4sy6t zdJLeF9^t;p2jH7XySQ)i;bD9e&+PEHFFhkYZ-Mw62XQ~>LTMK_B0p?rMA{`@mEPeT z?w0mQd!^T;ebVdF8`7K7ThiN%fcfw#BVay!&d3*xe8~s|ZoXpVYeo(>N$-X^{Lr!o zrB67A-`E^}Z`*^voZ#>{aQFk~@JB|zwK@C+IHadbzwr-$>Xg9p0R9am>ULlMBO^}Y zzl{7)FJnf2>==o%Lv{gGvdBsN2}qPBPU6ppAu)nJ6BZ`BAiKF=Q zkx-O7%SnKu+(qsxcayuzJ>)pKryMUQ$S`g9J0pKE@+TvIG4eMf|1k0|qli(=C~1;= zSt!c=~Ec?7^HpTwvThEYBRV3bFpRQ_Sq z!IN0Q7ofP?relme4p5ZGGU}|C3mA2E5XDLIR8G}Fc?t~9RN_=k2db#tj;e@^XOl)} zgr`w<*mCE{^DQdp0hLrgN_o4)V!4`ASt6IpKDkUTmn-B-d5OGKu42@~DCF#lWHgG= zXhvfgjb*eGqn#P;(j?bd#-bds25Na3r?P9mZL;$=6yuUc-6p36`G>>-YhR z`1U|zJ6)Z;L2k4tY~U0o9<7v(;Wqgmj$xC0i+roRUA|4eUA{xUQ@%^So6%m3_GYvX zqrg``M*A~5fYE`B4q`O9NxnCX;REu6@y%l#(JL)y`77x_{ChjaOp z{ImRv{Hy$%{JZ>z{HOev{5PX8B*4W1S*I{MiqX-G!ab71XfC69P4d4MmkLz`{?MP| zD6U(g`k)J(o%haH+s>H73lZ(gnCY;wvJQcqI{-R1z2+SFgZ}LJK;^ zq|#RzU@AzZKUa|BVZc=e@d0~6JE9`Q-;+jLM4~WVN`^ATRFukK4&>ycl(tKpq(B15 zCgo&hq;iTfN*S$WD>+K8lBeV|I+f9Bj812?kkKMWXD~XG(OHbnW^_)IGB(WP1k0aM zrf?qT+B_}{`!lrU1dYdm#s!?lg^bR#Y4ie(%3`I2e;A$5=mP5-^kjl(uHD;9lqyc; zQbvpGm1;&8b&$$a75=Qf65yKB3z|}?sH{;gR4!t)lF>Rw;R#mA{|1Q>+vRGtvaJRu z_#hkVki#9ov$R4Q!_u}%RC88Z1pV3np4KNyHG-MSvJttJP0D7Ti;a}mbgXP3`Y(gwdK)rFwkqQjklQ_GoHVMZq%DM-f18C@F@qHH{N4! zd@KgYtF@bFhw?DW*a*$@fbyX7kl8rP7+ucjijB%n9_5%~?v})p}4_qw>7+qM2{i`n@MC?-f%@|FD#Fkdih$eOO*r zX72D|rj*Ls3V)5yAG9R+>~eelhvoMDKbEt*;|=9)cy+t-rt%h}XEJIuDDNomGRhb| zi#L78FW~>RNlnB)YGLH@W^g_+Hx7Gnjk0%4D{wwnzT}$f3r5eWR{*nfjl2bLXHJG> zZdTLtyT`t)Z^9{)<$L7^kC36OOLgqFmJ+4Z=ll4GiJA`!hYjBkZ&EC z9Vn@&3_&L6x`1y^bKzo7Olt{~AQ@(rl>qq=$?(c~c+GyuH`5|}hWSsiC$V%{sMI`X zNI+cTtxASOX0>%8Utom!v%(LW(ZqkQRgULIn>)!{QVj`6hYzwd0;|z#7r3F-7&TVy zq=MgmHKW%sdM%^ZZB)Ce-PG=C4@R$N6x7{~jNZhl;yG;FCciGK4Dpui+-?WFp_wNk zJ>0G-wLD8Ov}anoQsKPYu)DCXx*9U^g$ePM^Bmg28D>JgS?PoGGcqz3dk&Z{ZBYBF z0~^(TYJYVAqc=0UkF@ng5vk6V~|@NtB&KtL@DGdoDv}@iy^^aFqD?|8YWb5h)#KS zFGwxRdt^>8FQ*cI74-`FYiIWgCyb9o_`D6Ko`f;cS8AdQ2kmxAMFGD*WZ>I9T@*Dc zx_giQ1JXvEbaK+j?1J$VCQd4xHG6(>I48ZPyFC$+kmDeHRaSy)NPv(X0;Rhc7!4W( zvToBkg>@w*K3}P?bZ<5_(7j9fgAImc&fTn3)R~&JH$8fqJJAEg> zIfW-;3@0L=QNU&7Ktk5N`oKZSDXGPtPL|x3dYj4Zdgz{37Z@99V5r~4uPl8?x5kXj z!G>hWhSHcdbeN$U8sub;GSg;rf&3zx3m1FhCl}@x@$F+Ey#{CvI~hf*Lps}s%qW-< zgtzH8@7fcqpEA0Bl%X5ZTy{==w}#w2!)Hp_Xi3};m)co ztMmb@otpO+t*rI6?C~IvxM%W|snZUZy}V75?}n+#Ni>NigUMvb!!n)BB8$mVvVyE4=RjtT zYas8&Mo5P75P6yGCZCWm$#>*O@*CBt$8sDA4m*$~;eW&b@c7sk(+*O{s}mM9_XgOE z-bUCo5tTs`@?W;XoUG138Jj_2PF1I=X=1nbC#LK2osAvwz>>bdH9>iOyg>KgSzGl9yB#_PskkZ5I(@ucx8qxUg-Kcf#a`Y@x9 zF!~rjk9m+Mdp=r#7OIyS@LGLFcN~wmV~;u9EAG|xmc$2+cP0k)T1(JF{~Kva)SE0} zJCEnsDG+| zsedyHae?<3eV@?}Hmd(>NW<#CjDE=IM~v==Kln99gBk}9(j+x!C3i{95LyHevo+Vx zH-ptY0}`Pf?%>W=9lp{T1#RmIpO+?SGK$@>fd~D#!`Pf?(j9S=$)>jL}c0L^$NO?onBJ z^&D{1tIe|pPOIRev%xU%mcP73SwUBC$`^Q|TWI{mjp@IDh_kf&eeWM%`tF^9l22`4vv8QvFj?@KJ zbnDS5caLpdgNN+lK3B)jh9*F8hBhIY7yeuW=H4Z}}r$Q&`l95p?TJtI#U z_5V=*D=43RQiD8VPi|g*hs*Wf`x=xRt2bt9@}7e69T5n}Pt+Ub5tC*^Pn+ku2b{DH zOYB$p6Vy-$H593>`)be3S<^bu=TLTzUN7&NH-ABgMfQL0TPRlSZIBnWmgu2-N=khl zkZE;tGEFf5NPFO(yFAmdu3Yl%=GcRFN~m$iEsqybX{L@qY3Qd6B$I-Xial?0Rvb@R?E*;BDrrE92yo^JhQMkGri?FQ}Gpo@ljLW5}>dXJ!n0(LU$bLnOxW&oM)aFk3RB{X{7n95DX=V%aoWy7sQNV z#LV%AN-DTbQRG_@GD{bg!LQe~leCkyk=iNRC>RGvYuV^Bv_Q+#^5=MKN-7{~SyMj8 ztg^@#sGd{JE8!l%+!|FmU_!>KdX_fZnow+RDYNP}P1&H$;WGHN<57;9Y9laTD+M1# zTc9n}inT?WS6i&XwCo>@{>kWHjDmUf52ODw0d3KIFps`VtI#U7CE%k77~B%Dnh6t} zOmJ}@g}WGG7h*b?e3m;O*hTm~uJ92lxn$v8*FB4xSLP4+n(F~GlUE+LKCQC6RmOP1r9aa7#H?DC zHYh%A^`Q7w8G|zh#iwTs%UHeIZmeb63U0M6X9BI)Rx&~0RvVXM2DpRSK`zBUc(ryW zL`bwVnBb__3?_(1Li0E_6-?3=N$EpDX2#(37D4A}FuQCETEhg%$g``xSi7{P+RK$OLj(Cw&h#FPk9)7CXOCNn476tz>ggkF6I4zlJ+_F3~J zQPDB6Gs9CPFjAQFMOIieCgfl0s~J=2t17iZ>E`VNu42Gf0?v$e2b*_1=rNzADst*V zAwQJiqgczp7&KfS1amHeA@1p{b?FK-BPrntpA81x)4fMr&%?#^?GSxKTzpG7zq6K@ zw83ydq27HCjfM7(i--FACDr#goQA_vY=@ppvE{ku2Lk>8RFa$mCtnOEfpr`xGH}(J zT^sX?H>Reg$N%S1pd?$WDdH_>+6dt`J9MAfs^-2Ug#Qx|I0B51=&~4}yv>VoB z?L%*%x6u3OOLTynf#@&nz?vEOx5EB?@DMy4pMpn&Ntg%5;8J`sUJEAR%ZHd>;Z@nT z`GpU3z!QE-dxj(YG!x?LwP%?CSzV4&ihIH@f+zg)e|o|~{FDf+ABwy7Klg+;m^OLj znO*;CaLEml)MAq>>S1hheGg0)#vI}tH%3N9bKe*|PWWz<=NG0@&2EeLm&J#`&WP`8 z{_GoH;SI*u_~Wa6)r)MPBG#Q;lTMCmzudh;G`?sEMR z@K-knuk4fhM*9>FFoX$NOc;8r_Lugz_K)^2O4YGWbgB!wLlNSNiLCtjvx9nmc(D%?%ea zLsRj2zA`TqpUS7YgZxt427sVB23STAUuXbpID-BfGpGeC$pYbaZ(W}|Y(|;!7ITIv zswHM)o{AO5Oscg`(+)wJ^XsK;WyAH^rj~t}&ud;r0oZRV!11V9ILW)BvKl6YVcrs; zg6Jn$PT@;xB`xNV^5(&CX_4Vpn&>MF75S%EmRE$rovU}!VXa5K-kAv_>h-QnIElA+ z1nA!8b~Hy56I(q_9oV4v)Z>`|eFck_?WGiYk`AvHZq$3}y>$o)gK2vT6Gk=a{ZL=*1G-4%PGY zd~4_H`Z&EnACKJn1bw1DNuR7w(WmOu978}G<@rnM_!<;@jnBfCOXOV#_h0iJH64~q zz?kNhtvlaE%KcL-a*+TV&5L&x#3? zKq?a^&o1}Cc~*Lf4$eq-=&Y7_faUjv>8%Vj=sxaO9rYMnb~!y=U&Mr|{7F4w za!X9c-d}~+@%_^wH{8j7eIVI zFx^{I?wjZX2i?OLT5(@JzXqbsPy{wvWhX+^q`5jR_8A^#@80fVayunlajaJ7B|I4$}$`nCFX`t?j$$b@1h09xLS`i=Tc&c*r$CM;$`IU_j? zGMXjK=BkyeuQ{f6HOC)I=~`1GJZ{mfQJXckEpCer8AUhhTlH;vlYR?>v}!^r6MRf4 z+Xw@BDyjurU?e;b(=%)ln2QYIZU^n@TW*fw)4j`0n+KGA*S34ZPP`e+fsv-oPP4c_ z&}uyml#gw5h*>-LJ?wMcp+CR}jQg2TQ4ddzootR5U_J!>Rp9^vzhe97NA$<|(coV# zsn;R$vGi!e%Ts)Kd0Kyl2~|w+w;Eoa*Iz!IzK0Z9`fesv^H@rak=NV@Nu$qfJ6^o5 z!)yB54^QvFc<~++YWa9^s*%^ybxEU*56v1ZjkzBdX6PR?0hV+(k9eQy2Vn+L|6Kn< z|587of2DuTgb)+zm;j0iq8uxjuyV8hjsC6v9en@5qduoGVHFcVgTf!Tanr1gg%V+n zb=HKkJ<40##(~8GW+ZF`yKRBBjW=?7=D>Me;ZLZnDK#hMdO&a0Rh9BSn_5>@HJ$6} zUkH-=S&`ak-=Zp4JsnXsA(XEeGAf7FEuXF{i%-5Loe1Cg1q_^?;$ zv27LDX=-=~y94?RAj&0a2No_z*0rb8&RoBgZBcyC?~$ApWSa3Mr71;&I+nQ)2m3llDCV`87mMR*9yLew4}Ql|RKy}`PmHHXR9Gq()uFtmCh##vL^Z*e7rHcMgc^oah}>E*k} zzhH51k{ zVf$e*br-se++FmA98;^~nQ$Ew)|ov&=`cM%*FCSL=dWb~#1z9uo89y998aTrvAe_# zN`5^Pu42M9Ej=GLfUZ1J&xZ}5tN&*`AJ)t6mF{!kkudjZ?p5y7-K*VaxX*MOZstDA z4J5*NcLRfDi~>Y2Z)O6FboESVU_v7kHa5A>g%JrB+PK$PPjI_0fk(oGO`y(Ttql{l zgrDFRPGsM*AWI2?GS03G!DI`Jt=(Jhf$(l_5RHLVuBNHjwcYOJu)KvEiB{ae4apPg z-OxFk4eJSR_sw9;AMpup_h$E22oSlqFkx%Gdm9tBai^$jp06t8wZvN{O0$Zy>DcZz zU!ix^*SbwGuP9L&*wYdP^{ggTm7QX*;Xgq7+ z|8(K|2cAfm#FuKAYub6Nwo~UWUAys!Xp$L)8@QnlwEJLt6Pv~UDen?t$7*THYi;I!C~t}ElLm}( z9GsUtIBn>VR=VroEzU<8WVd)U(;z-1&@d+vT0x;n3wD^o6S>azZ;KD`> z^Lt_-yc>W|G77@--AYu3LMT2y8pWe=$cI+IYJleLFl+&y%@=E36U_2l?xV8&dsAu>L<{?BEg%%l>o|Qf%ZAf}@*6^XwEJJhhl85DI=OpLmr47#=GB^`jCvE;Je(f+p zH+XQ`>OEt|jw?7^pdY%b^$9eL8{Zu7e{JHVp_8ZdojMKL*6vX2G+UQ2JwXW3w>_dg zJ6+ly&1m81<%YZv^lMQ5P%AmqOZZAbT@ov`ZT0QvECOFBJt;j8uebU@Iv{;7{UZG) z{UQA;V_A?zc-v5(JPqFMvP7aV`AYd}`C9n~`DVF6-Xw2@ zmvC%{*Kgb{-z&c;e<}a1$V!4zq?9RV!-J|jls(E`nU5&2@|zQ{Ks-->)E^1a9pB0q}UANg(M50O7b{u=pvBx-2X@TmN#qNrI>i=uo{HBqagjHt7s&WTzRby3tMQI|zs8MQHL zd(?wbyQB6-?TdON>aD1EqTY-8AnK#2kE1?~`aJ5NXcSGNg=jI_6)i`r(R#EeIx;#s zIyO2pdV2J-=xd@Mj@}&nMa<7Jf5iM1^G_^|b;LSjrP$7~-C}#irpIQ*4vQTTJ1RCi zHa9juwkXycTM@e?wkozJwk~#g?8?|xv8!V*jJ-Ja(%8$pq;(nDWmK2!F1g)ycYD9v zhu!vf`y}q1xV3Sc{%#oZcrTihLScg5WkcVFE7aSz7561O{UZ`{7PH{#xkdnfL_ zxDVn!iu*Y3)1IVfLeKo3*ANkuZ+JczA=7ld{g|b@ps1G9e;29j`*kJUxxbNKQyiNKY7(FfL(y!o-Bh2~!iMCln>j zOqiW8H(`Fl%7kkY9!_{aktFs@oS3*Y@xsI{iFYL4op^8Jj>N|jpG$lp@ukF95_c!= zO?*A^&BV78KTkZ6_;up9iQgywnB+<7k(8L!E2&S?z@+4))TH#J(MkD9lar<;Eles& z@+FlgRVCFV)g}d!Skk3QjY*r5wj^y!x+Q6Q((OriCf%KMZ_zTATmVl zOq{eFNEwJIAfnuLmF>Lh+Lq0$Yj^E&t!sSm_4>TNKRtiM`*|KfE+7w343Gdy0CK=4 zKq+7wpcCK#I03x?FTe*F1pERx0XPj90gM9f1D*h$0-gij0Nw%K13m&L1Lpx30ha)O z0Ot zfwDmY&_<9RR0FC7Z3S6DHc%gEFK9n#2y_T^95f6%4;lsC1U&&g1HAyf2E7IS10DyS z0-g^hgDK!Fa5k6$W`c9Ud0;M>2j+td!9`#ZSPYhcOTZh!3a}Ea0+)fy!8))3Yy?+< zH-l@ywcwNB)8Mn<3*Zs(DEK<~7WfYM9{3^n3HTZKCHM{aAMi);zu<3yV*@7yP7a(F zI3sX&;M~9kfr|o{1}+a=85kNE9vB%I9oQIX3A6_84%`#8B4}+;SWrYzR8Vcu&Y;$y z_Mnd7F~Ku}X9dp*o*P^etPR!&R|HoEKMwvU_(Slg;D19{Aw?mg5OIhkWF+LTkb5By zLLRM6Si5d5el1}wajkppzO@I|9$b4kba`k7{KV|Z2g=I|%s@54Wae-8f=L5yHVxs3TFwqE1Bp z9=$d?J~|;95si$tM!TXt(cWlZ%Jy%h)%u?_%G_ z&5etU%ZgLRwZ$EYdkC2bSp!Le;2;DD2||YCKzNV>ND-tMB7u}ZHbNAT3P=^?XGkri z9?}SLL-s)qL5@I%c8eRi8!5iRBa5H=xyc2GRcf)((9=I2N7JdVM2YwI!0RA`pIs7I3HDU~6JYqIt zKH^8jV#IR9O2irj5D|kwA!rB&f`!OKfG9!85j6-Cq8`zRXhv*9>_D_2 z+7KOxU5HM^A;j&(@ri)Mb%`4in-lvJFC@N5{E+xL@oVCD31!gm53&w zhf)ux9!nigJ(+qX^;+u9)Z3|dQ}1KPVrOFKV&`KQVt>M}z^=vuu+i99EE|yLt>~ZWc_7wIH>{;x2>?Q1F z>?ro#y1DD(*3s8#)^)BMUiT0;5w{8#j0?p@;G%E|I1CPp!{gF%8MsUw6-UGIa0R#` zTrp09E5X&{+HkvYoj5zL2j|9laX#D;+;QAR+$ioE?k4Up+{7?85 z_|0Z+n{@f3U(o{rDKv+!&@7th1<@fG;p_!IcYY17jp)3Va! zY34L<+HYwG(hj8^Njsf3k~W%lE$wF7pJ{i}?xwv=dz1E0+Q+ni)4mcG6F`IzLMS1E z5KDj%U<5cJjX)$Y2^>N`flm+;iU|@z2|-V&BXkn%gl>~^j4il~r zt`Tk!ZV_%1?h@`39ugiCo)VrDUZzh^4^AhhOVhWe?@Pa({*Cw(F`kGfrV!T=@k9!d zMa(1S6Zu2|QAjK%s)!n*j#xpgB5o$yi2cN0h0Xgs1z!V%Am5SdDMI= zpQ@&oQ*~4W)kv+T)=*8W)S6Oee z{-sTzO{Ptw&7jSu1<>Zv7SLAHfV4nb2rY~jK})CQ(DG=An6MhiGSLcWDo3k7-Y7FKDl6?`R)rpJ`vS$7IjXUYNZ&dujHv z?3LN8vjN$l?4azB?9gm{c2Ra+c3<{L_GkJsI-Jg=m(mUNO8RDc4ZWG(Mz_$d^xgD5 zbUWQg_tW>%_tOv357YmoKc&B-zoGv_|4jeN7{eIHn8TRMSit}=K#U+p7$cGq!-!*~ zFftj13?W0zkTNzhHZfET4MWGMU{o<$85V|>v751n(Zz5wTnrDRpE1DjGcGaS- zu;#NCvX-!xv7%V9EC?%}mB315C9%*f3=7M`vC>!q)@D{O>n!U{?!w%J+?-rh?)F@3 zZfCAN*OBYZ{VjKY?ojTb+#|WiaxdhLzE`vQcad8^=y#6WJN;Ja#eLz^-I(W^ZBFu^ZWD_I7p)yPa)i53+w{|Hj_W9%3J6 zA7vkB53^6P|6reGKh2w#7n(=P+nCpqHUBiWP6SxR2l8fSExT)NATs$|OOX8Bb8@P4ce(nhO zWB#&yR6ZwPm*1Xm&+pFf&3EVjl7A@wNdB?>6ZyaApUNN2zn*_9|4#nB{0F>oyji?? zydQasc*}Szd8>H&){eBseCSfJ-?7I%>^ zgnxy9jsGYA4*wqi0smdW*n$NGiwc$&EH7A904M+#1Q&!BL=;39tSd+>NG~82kPD~< zv;ulTPC;%#UIDj2TVN?TQgFX;N?~XrxlmfzQ0OZ37w#?GUpQ1aTzJ0lV&O>PmBOoq z*9#vN{$2RI@Kxd4!hZw-g5`oW0-zvJ5Gn{4LyH>C>Rlp3a$xm2yO}P2<{5*7mY1iQIuT7 zFRCf(D;gXQn!a?CL!V|(v!mGmT!dt?-!u!HU!Y9IyqKTr#qMt-7M5{$WQJ^S96efxk#fTsx zf`}v{izuQj5nYrcVu{!yu81e%iz-CBMJGg$i>DVy7H1X9i_OK};@^r76dx)+Qhd62 zr1(nl)#B^LH;ex)ep>vZ_;vBS;t$22#0$i$#b9xec&#{693zH^;6c>xj#6OEI;$7lB;x4gM>=O5hePX|OuXw-sf_OxHMSN9!U3^P?Tl|;!p7^2o zvH0%|lQ#f2;5LXhG;Hv1xW3_&WT7NRf{-Lhk|ik;q9j|ABVkGMBwPtk!k5S-3Q4J? zOrn+OB^F7Kq)+0L3`%~J9FQE89G0AyT$J3F+?PC*JdwPRypp_?{3D$pog)QG1EnF- zFlnSTMhcO_qzGw}G+9cQGNrlFJSkVYURod(NQF|dR3a^r)=S;ei_&)`3ri3s+!B3> zwd6p_iIS5gf0Udp87;X}a=BRPRjm}os->{ zJ(4|L%4f>g%5m~cd6t|m&yn-w z#d3+fL@t+al9$TW^3C!s@;Z5=+$`TF_sI{*kIRSUr{w447vv-IEAj{O$MVIa%S|7ZW0m8T6P1&dQHXw34KxDrriFlC9(_*DDK@3T3IXO1VX8QZ^{JDt9PbmF>!2>RvoU6Qpc#1)fsBOTA&uGH>gY0awYNL9mx=n3STh+VOHnl_DqjstL)cxuK^#%2-vUz2(WsEXi*`BhaWp~TIYo=&^ z(9G1#)-2Mj(yY+{HDFDUCPV|(Bxn*fC=EuFs^Mv*8ihuwQEPM>gQikbt=Xp8soAaZ zXa+QX&0fur=8)#7=D21=^Oxqm=9A`&=6m_L@`>eB%6}-ISw5$HUU^`7NO@>^czI-b zOnF>6v>aBBC`Xo~%Gu@R<-5y|l|RyR>~;pVqJ4tKF|1 z(jL+t(Vo*@)LzzJ)!xwF(tiGLVKDtaG?=4Xpj)I{s#~U8s|){6rct_NU8*ikN7RvZ z6kWbfqT8fX=`=c>u3A^4GwB+1O*)_MseYb*r9MO-rjOLe=plNTK1IJypQb13$$F}u zrq9t!^hW(oy-V-c59x>Xr}UTf*Y&sckM*zh@AO{{lMGW00fr@pWd@KT+z@3z8rB)o z3`7IjKsDqVI0l}fz))lm8T5v22B*PiIAAzrcxm`pF|A@w#o~(96~GE|MNUO-MNLI> z#kPtg73V5ODn=`=SKO|+Tk)Xck#VjOWyBjPMw&6tC@_kQrN%O&)@U$R8mo<4jXRBY z<6h%_<3ZyQ<8kBf#?!{L#tX&~<0In}<1^z6<7?wP;|Jqs<5%PN%CVKxD_2)0R1z!s zmFmjM%Jxcs<$=nhm5(c5RDPsk0jt8QBCBGmAXTs`cvV)Fw5qo1 zVAb)eGgarRu2$Wyx?A<2>T%W6s*hFQtH)JOte#Rmt2&^1e)YoY#ntF)X?1&bM|E$t zui9U|w|al|(dy&XzgM5GK2tqXeXIJxmUmk|)Q+j0Sv$XWX>DL_Y%R1lp*FD=Rg0;` z)>3P;YjbLIYdN*N+Jag^ZC$Oe_Lga~X|`#RX_X0JiZ;PbX{JmQ)5JD$O!+2>NoJCp zlqR)FW2!R!Y}#U~Gi^8RFtwWYn2wuH%F(#GIM zN~5-MSL1=ktBnsDKQ{i`_^oMd(}bqUP1BlYG|g_B+XQR^Hw8C^Hbpc=H^nu@HzhPB zHYGJtnhKiKO?6GXn>S_PZ)|RAwm1LU{Acsi=6B5>nm;#xHIFe*HBUFsG6$IFn}0Nino;H)v%*|qHkvEV z)#lx1kGbDGX#Ul_&wRjq)%=(F+t#sLC$t2#ENMw@!MAK|xz_Tq&??c#Pxdr7;zUD>W~*R*Tf>)QL;|7gEwnPFLO zL0Ymc>n(*Ap+#(wT4a_=OOs`*WrwBJVzF2)-4>_iu;r}ff@Q=qYPoK?X?bFKW_f9O zWBJGOp<_bF1avIxNa{%Mpmi`hSRHvC`5mH;4IL#N@(yK(s-vT0xZ`i@ z3~Q7%!t|wOzBlw$HV%utV($_C!0%jA5E3u2(rS7tHxw?*a z-ROGN_0=)PG2SuBG1c*dW4QzDSnCLPL^)y|Xa~+gaF86C4u*r}U^}=Do}BJ z95zS4W3OYsHh8<=bYf2<6P=o6YgX> zIZmC^nw)O1n zY3ssns z?poynxWKLmSF|h674L$(5?xpq*~N0nT?W?{SDmZTWp-_MSzWtbdt7#x!{v1S?t0*! z;$Gt63JbQihH-PP_|cfGsGz16+j-RoH^dv}jr2x) z-gn7&$9LEF!1u`aZeZ%b^nqCe0R!^~77i>KST?Y7V9fw%AYmYJAZY+SfEmCJ;0DqL z(g!jIG6$#wB?FBEg9D=j{|>Gk#0>HVD+aBD-GjY@o4nFoz^auEV^e^%+^{@1=_5=N3f1E$rzs`^Mr~5PgRDZUg;TQNz{5Af1 ff0uu+|FZwjeRuvx^W(<-FJ}$^Kh^&)_uczHJt1;i literal 52460 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 k2g&Z_: Error, CustomStringConvertible { + // MARK: Stored Properties + public let actualValue: Value public let expectedValue: Value - public init(actual: Value, expected: Value) { - self.actualValue = actual - self.expectedValue = expected - } + // MARK: Computed Properties public var description: String { "\(String(describing: Self.self))(expected: 0x\(expectedValue.hex), actual: 0x\(actualValue.hex))" } + // MARK: Initialization + + internal init(actual: Value, expected: Value) { + self.actualValue = actual + self.expectedValue = expected + } + } -extension CRC { +extension Checksum { - public func verify>(_ expectedValue: Value, for bytes: S) throws { - let actualValue = calculate(for: bytes) - guard expectedValue == actualValue else { - throw VerificationError( - actual: actualValue, - expected: expectedValue - ) + public func verify>(_ expectedValue: Value, for data: S) throws { + let actualValue = calculate(for: data) + guard actualValue == expectedValue else { + throw VerificationError(actual: actualValue, expected: expectedValue) } } @@ -50,21 +53,3 @@ extension CRCCalculator { } } - -extension FixedWidthInteger { - - internal var hex: String { - withUnsafeBytes(of: bigEndian) { $0.hex } - } - -} - -extension Sequence { - - internal var hex: String { - self - .map { String(format: "%02hhX", $0) } - .joined() - } - -} diff --git a/Sources/CRC.swift b/Sources/CRC.swift index 59aa997..a4d8295 100644 --- a/Sources/CRC.swift +++ b/Sources/CRC.swift @@ -6,7 +6,7 @@ import Foundation -public struct CRC { +public struct CRC: Checksum { // MARK: Stored Properties diff --git a/Sources/CRC32.swift b/Sources/CRC32.swift index 5f29080..627ef7e 100644 --- a/Sources/CRC32.swift +++ b/Sources/CRC32.swift @@ -17,7 +17,6 @@ extension CRC32 { public static let posix = Self(polynomial: 0x04C11DB7, xorOut: 0xFFFFFFFF) public static let sata = Self(polynomial: 0x04C11DB7, initialValue: 0x52325032) public static let xfer = Self(polynomial: 0x000000AF) - public static let c = Self(polynomial: 0x1EDC6F41, initialValue: 0xFFFFFFFF, reflected: true, xorOut: 0xFFFFFFFF) public static let d = Self(polynomial: 0xA833982B, initialValue: 0xFFFFFFFF, reflected: true, xorOut: 0xFFFFFFFF) public static let q = Self(polynomial: 0x814141AB) diff --git a/Sources/Checksum.swift b/Sources/Checksum.swift new file mode 100644 index 0000000..1f86abd --- /dev/null +++ b/Sources/Checksum.swift @@ -0,0 +1,14 @@ +// +// File.swift +// +// +// Created by Paul Kraft on 26.07.23. +// + +import Foundation + +public protocol Checksum { + associatedtype Value: FixedWidthInteger + + func calculate>(for data: S) -> Value +} diff --git a/Sources/Hex.swift b/Sources/Hex.swift new file mode 100644 index 0000000..2c4f040 --- /dev/null +++ b/Sources/Hex.swift @@ -0,0 +1,26 @@ +// +// File.swift +// +// +// Created by Paul Kraft on 26.07.23. +// + +import Foundation + +extension FixedWidthInteger { + + internal var hex: String { + withUnsafeBytes(of: bigEndian) { $0.hex } + } + +} + +extension Sequence { + + internal var hex: String { + self + .map { String(format: "%02hhX", $0) } + .joined() + } + +}