| 2cd40ea1 Andy McCall ↶ |
1 |
|
| 2 |
|
| 3 |
|
| 4 |
|
| 5 |
|
| 6 |
|
| 7 |
|
| 8 |
#![cfg(all( |
| 9 |
feature = "ffi", |
| 10 |
any(target_arch = "aarch64", target_arch = "x86_64", target_arch = "x86") |
| 11 |
))] |
| 12 |
|
| 13 |
use crate::CrcAlgorithm; |
| 14 |
use crate::CrcParams; |
| 15 |
use crate::{get_calculator_target, Digest}; |
| 16 |
use std::collections::HashMap; |
| 17 |
use std::collections::HashSet; |
| 18 |
use std::ffi::CStr; |
| 19 |
use std::os::raw::c_char; |
| 20 |
use std::slice; |
| 21 |
use std::sync::{Mutex, OnceLock}; |
| 22 |
|
| 23 |
static STRING_CACHE: OnceLock<Mutex<HashSet<&'static str>>> = OnceLock::new(); |
| 24 |
|
| 25 |
|
| 26 |
#[repr(C)] |
| 27 |
#[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| 28 |
pub enum CrcFastError { |
| 29 |
|
| 30 |
Success = 0, |
| 31 |
|
| 32 |
LockPoisoned = 1, |
| 33 |
|
| 34 |
NullPointer = 2, |
| 35 |
|
| 36 |
InvalidKeyCount = 3, |
| 37 |
|
| 38 |
UnsupportedWidth = 4, |
| 39 |
|
| 40 |
InvalidUtf8 = 5, |
| 41 |
|
| 42 |
IoError = 6, |
| 43 |
|
| 44 |
StringConversionError = 7, |
| 45 |
} |
| 46 |
|
| 47 |
impl CrcFastError { |
| 48 |
|
| 49 |
fn message(&self) -> &'static str { |
| 50 |
match self { |
| 51 |
CrcFastError::Success => "Operation completed successfully", |
| 52 |
CrcFastError::LockPoisoned => "Lock was poisoned (thread panicked while holding lock)", |
| 53 |
CrcFastError::NullPointer => "Null pointer was passed where non-null required", |
| 54 |
CrcFastError::InvalidKeyCount => "Invalid key count for CRC parameters", |
| 55 |
CrcFastError::UnsupportedWidth => "Unsupported CRC width (must be 32 or 64)", |
| 56 |
CrcFastError::InvalidUtf8 => "Invalid UTF-8 string", |
| 57 |
CrcFastError::IoError => "File I/O error", |
| 58 |
CrcFastError::StringConversionError => "Internal string conversion error", |
| 59 |
} |
| 60 |
} |
| 61 |
} |
| 62 |
|
| 63 |
|
| 64 |
thread_local! { |
| 65 |
static LAST_ERROR: std::cell::Cell<CrcFastError> = const { std::cell::Cell::new(CrcFastError::Success) }; |
| 66 |
} |
| 67 |
|
| 68 |
|
| 69 |
fn set_last_error(error: CrcFastError) { |
| 70 |
LAST_ERROR.with(|e| e.set(error)); |
| 71 |
} |
| 72 |
|
| 73 |
|
| 74 |
fn clear_last_error() { |
| 75 |
LAST_ERROR.with(|e| e.set(CrcFastError::Success)); |
| 76 |
} |
| 77 |
|
| 78 |
|
| 79 |
static STABLE_KEY_STORAGE: OnceLock<Mutex<HashMap<u64, Box<[u64]>>>> = OnceLock::new(); |
| 80 |
|
| 81 |
|
| 82 |
|
| 83 |
|
| 84 |
|
| 85 |
fn create_stable_key_pointer(keys: &crate::CrcKeysStorage) -> (*const u64, u32) { |
| 86 |
let storage = STABLE_KEY_STORAGE.get_or_init(|| Mutex::new(HashMap::new())); |
| 87 |
|
| 88 |
|
| 89 |
let key_hash = match keys { |
| 90 |
crate::CrcKeysStorage::KeysFold256(keys) => { |
| 91 |
let mut hasher = std::collections::hash_map::DefaultHasher::new(); |
| 92 |
use std::hash::{Hash, Hasher}; |
| 93 |
keys.hash(&mut hasher); |
| 94 |
hasher.finish() |
| 95 |
} |
| 96 |
crate::CrcKeysStorage::KeysFutureTest(keys) => { |
| 97 |
let mut hasher = std::collections::hash_map::DefaultHasher::new(); |
| 98 |
use std::hash::{Hash, Hasher}; |
| 99 |
keys.hash(&mut hasher); |
| 100 |
hasher.finish() |
| 101 |
} |
| 102 |
}; |
| 103 |
|
| 104 |
let mut storage_map = match storage.lock() { |
| 105 |
Ok(guard) => guard, |
| 106 |
Err(_) => { |
| 107 |
set_last_error(CrcFastError::LockPoisoned); |
| 108 |
return (std::ptr::null(), 0); |
| 109 |
} |
| 110 |
}; |
| 111 |
|
| 112 |
|
| 113 |
if let Some(stored_keys) = storage_map.get(&key_hash) { |
| 114 |
return (stored_keys.as_ptr(), stored_keys.len() as u32); |
| 115 |
} |
| 116 |
|
| 117 |
|
| 118 |
let key_vec: Vec<u64> = match keys { |
| 119 |
crate::CrcKeysStorage::KeysFold256(keys) => keys.to_vec(), |
| 120 |
crate::CrcKeysStorage::KeysFutureTest(keys) => keys.to_vec(), |
| 121 |
}; |
| 122 |
|
| 123 |
let boxed_keys = key_vec.into_boxed_slice(); |
| 124 |
let count = boxed_keys.len() as u32; |
| 125 |
|
| 126 |
storage_map.insert(key_hash, boxed_keys); |
| 127 |
|
| 128 |
let ptr = storage_map.get(&key_hash).expect("just inserted").as_ptr(); |
| 129 |
|
| 130 |
(ptr, count) |
| 131 |
} |
| 132 |
|
| 133 |
|
| 134 |
#[repr(C)] |
| 135 |
pub struct CrcFastDigestHandle(*mut Digest); |
| 136 |
|
| 137 |
|
| 138 |
#[repr(C)] |
| 139 |
#[derive(Clone, Copy)] |
| 140 |
pub enum CrcFastAlgorithm { |
| 141 |
|
| 142 |
CrcCustom, |
| 143 |
Crc16Arc, |
| 144 |
Crc16Cdma2000, |
| 145 |
Crc16Cms, |
| 146 |
Crc16Dds110, |
| 147 |
Crc16DectR, |
| 148 |
Crc16DectX, |
| 149 |
Crc16Dnp, |
| 150 |
Crc16En13757, |
| 151 |
Crc16Genibus, |
| 152 |
Crc16Gsm, |
| 153 |
Crc16Ibm3740, |
| 154 |
Crc16IbmSdlc, |
| 155 |
Crc16IsoIec144433A, |
| 156 |
Crc16Kermit, |
| 157 |
Crc16Lj1200, |
| 158 |
Crc16M17, |
| 159 |
Crc16MaximDow, |
| 160 |
Crc16Mcrf4xx, |
| 161 |
Crc16Modbus, |
| 162 |
Crc16Nrsc5, |
| 163 |
Crc16OpensafetyA, |
| 164 |
Crc16OpensafetyB, |
| 165 |
Crc16Profibus, |
| 166 |
Crc16Riello, |
| 167 |
Crc16SpiFujitsu, |
| 168 |
Crc16T10Dif, |
| 169 |
Crc16Teledisk, |
| 170 |
Crc16Tms37157, |
| 171 |
Crc16Umts, |
| 172 |
Crc16Usb, |
| 173 |
Crc16Xmodem, |
| 174 |
Crc32Aixm, |
| 175 |
Crc32Autosar, |
| 176 |
Crc32Base91D, |
| 177 |
Crc32Bzip2, |
| 178 |
Crc32CdRomEdc, |
| 179 |
Crc32Cksum, |
| 180 |
Crc32Custom, |
| 181 |
Crc32Iscsi, |
| 182 |
Crc32IsoHdlc, |
| 183 |
Crc32Jamcrc, |
| 184 |
Crc32Mef, |
| 185 |
Crc32Mpeg2, |
| 186 |
Crc32Xfer, |
| 187 |
Crc64Custom, |
| 188 |
Crc64Ecma182, |
| 189 |
Crc64GoIso, |
| 190 |
Crc64Ms, |
| 191 |
Crc64Nvme, |
| 192 |
Crc64Redis, |
| 193 |
Crc64We, |
| 194 |
Crc64Xz, |
| 195 |
} |
| 196 |
|
| 197 |
|
| 198 |
#[allow(deprecated)] |
| 199 |
impl From<CrcFastAlgorithm> for CrcAlgorithm { |
| 200 |
fn from(value: CrcFastAlgorithm) -> Self { |
| 201 |
match value { |
| 202 |
CrcFastAlgorithm::Crc16Arc => CrcAlgorithm::Crc16Arc, |
| 203 |
CrcFastAlgorithm::Crc16Cdma2000 => CrcAlgorithm::Crc16Cdma2000, |
| 204 |
CrcFastAlgorithm::Crc16Cms => CrcAlgorithm::Crc16Cms, |
| 205 |
CrcFastAlgorithm::Crc16Dds110 => CrcAlgorithm::Crc16Dds110, |
| 206 |
CrcFastAlgorithm::Crc16DectR => CrcAlgorithm::Crc16DectR, |
| 207 |
CrcFastAlgorithm::Crc16DectX => CrcAlgorithm::Crc16DectX, |
| 208 |
CrcFastAlgorithm::Crc16Dnp => CrcAlgorithm::Crc16Dnp, |
| 209 |
CrcFastAlgorithm::Crc16En13757 => CrcAlgorithm::Crc16En13757, |
| 210 |
CrcFastAlgorithm::Crc16Genibus => CrcAlgorithm::Crc16Genibus, |
| 211 |
CrcFastAlgorithm::Crc16Gsm => CrcAlgorithm::Crc16Gsm, |
| 212 |
CrcFastAlgorithm::Crc16Ibm3740 => CrcAlgorithm::Crc16Ibm3740, |
| 213 |
CrcFastAlgorithm::Crc16IbmSdlc => CrcAlgorithm::Crc16IbmSdlc, |
| 214 |
CrcFastAlgorithm::Crc16IsoIec144433A => CrcAlgorithm::Crc16IsoIec144433A, |
| 215 |
CrcFastAlgorithm::Crc16Kermit => CrcAlgorithm::Crc16Kermit, |
| 216 |
CrcFastAlgorithm::Crc16Lj1200 => CrcAlgorithm::Crc16Lj1200, |
| 217 |
CrcFastAlgorithm::Crc16M17 => CrcAlgorithm::Crc16M17, |
| 218 |
CrcFastAlgorithm::Crc16MaximDow => CrcAlgorithm::Crc16MaximDow, |
| 219 |
CrcFastAlgorithm::Crc16Mcrf4xx => CrcAlgorithm::Crc16Mcrf4xx, |
| 220 |
CrcFastAlgorithm::Crc16Modbus => CrcAlgorithm::Crc16Modbus, |
| 221 |
CrcFastAlgorithm::Crc16Nrsc5 => CrcAlgorithm::Crc16Nrsc5, |
| 222 |
CrcFastAlgorithm::Crc16OpensafetyA => CrcAlgorithm::Crc16OpensafetyA, |
| 223 |
CrcFastAlgorithm::Crc16OpensafetyB => CrcAlgorithm::Crc16OpensafetyB, |
| 224 |
CrcFastAlgorithm::Crc16Profibus => CrcAlgorithm::Crc16Profibus, |
| 225 |
CrcFastAlgorithm::Crc16Riello => CrcAlgorithm::Crc16Riello, |
| 226 |
CrcFastAlgorithm::Crc16SpiFujitsu => CrcAlgorithm::Crc16SpiFujitsu, |
| 227 |
CrcFastAlgorithm::Crc16T10Dif => CrcAlgorithm::Crc16T10Dif, |
| 228 |
CrcFastAlgorithm::Crc16Teledisk => CrcAlgorithm::Crc16Teledisk, |
| 229 |
CrcFastAlgorithm::Crc16Tms37157 => CrcAlgorithm::Crc16Tms37157, |
| 230 |
CrcFastAlgorithm::Crc16Umts => CrcAlgorithm::Crc16Umts, |
| 231 |
CrcFastAlgorithm::Crc16Usb => CrcAlgorithm::Crc16Usb, |
| 232 |
CrcFastAlgorithm::Crc16Xmodem => CrcAlgorithm::Crc16Xmodem, |
| 233 |
CrcFastAlgorithm::Crc32Aixm => CrcAlgorithm::Crc32Aixm, |
| 234 |
CrcFastAlgorithm::Crc32Autosar => CrcAlgorithm::Crc32Autosar, |
| 235 |
CrcFastAlgorithm::Crc32Base91D => CrcAlgorithm::Crc32Base91D, |
| 236 |
CrcFastAlgorithm::Crc32Bzip2 => CrcAlgorithm::Crc32Bzip2, |
| 237 |
CrcFastAlgorithm::Crc32CdRomEdc => CrcAlgorithm::Crc32CdRomEdc, |
| 238 |
CrcFastAlgorithm::Crc32Cksum => CrcAlgorithm::Crc32Cksum, |
| 239 |
CrcFastAlgorithm::Crc32Custom => CrcAlgorithm::Crc32Custom, |
| 240 |
CrcFastAlgorithm::Crc32Iscsi => CrcAlgorithm::Crc32Iscsi, |
| 241 |
CrcFastAlgorithm::Crc32IsoHdlc => CrcAlgorithm::Crc32IsoHdlc, |
| 242 |
CrcFastAlgorithm::Crc32Jamcrc => CrcAlgorithm::Crc32Jamcrc, |
| 243 |
CrcFastAlgorithm::Crc32Mef => CrcAlgorithm::Crc32Mef, |
| 244 |
CrcFastAlgorithm::Crc32Mpeg2 => CrcAlgorithm::Crc32Mpeg2, |
| 245 |
CrcFastAlgorithm::Crc32Xfer => CrcAlgorithm::Crc32Xfer, |
| 246 |
CrcFastAlgorithm::CrcCustom => CrcAlgorithm::CrcCustom, |
| 247 |
CrcFastAlgorithm::Crc64Custom => CrcAlgorithm::Crc64Custom, |
| 248 |
CrcFastAlgorithm::Crc64Ecma182 => CrcAlgorithm::Crc64Ecma182, |
| 249 |
CrcFastAlgorithm::Crc64GoIso => CrcAlgorithm::Crc64GoIso, |
| 250 |
CrcFastAlgorithm::Crc64Ms => CrcAlgorithm::Crc64Ms, |
| 251 |
CrcFastAlgorithm::Crc64Nvme => CrcAlgorithm::Crc64Nvme, |
| 252 |
CrcFastAlgorithm::Crc64Redis => CrcAlgorithm::Crc64Redis, |
| 253 |
CrcFastAlgorithm::Crc64We => CrcAlgorithm::Crc64We, |
| 254 |
CrcFastAlgorithm::Crc64Xz => CrcAlgorithm::Crc64Xz, |
| 255 |
} |
| 256 |
} |
| 257 |
} |
| 258 |
|
| 259 |
|
| 260 |
|
| 261 |
#[no_mangle] |
| 262 |
pub extern "C" fn crc_fast_get_last_error() -> CrcFastError { |
| 263 |
LAST_ERROR.with(|e| e.get()) |
| 264 |
} |
| 265 |
|
| 266 |
|
| 267 |
#[no_mangle] |
| 268 |
pub extern "C" fn crc_fast_clear_error() { |
| 269 |
clear_last_error(); |
| 270 |
} |
| 271 |
|
| 272 |
|
| 273 |
|
| 274 |
#[no_mangle] |
| 275 |
pub extern "C" fn crc_fast_error_message(error: CrcFastError) -> *const c_char { |
| 276 |
let message = error.message(); |
| 277 |
|
| 278 |
|
| 279 |
match std::ffi::CString::new(message) { |
| 280 |
Ok(c_str) => { |
| 281 |
|
| 282 |
|
| 283 |
Box::leak(Box::new(c_str)).as_ptr() |
| 284 |
} |
| 285 |
Err(_) => std::ptr::null(), |
| 286 |
} |
| 287 |
} |
| 288 |
|
| 289 |
|
| 290 |
#[repr(C)] |
| 291 |
pub struct CrcFastParams { |
| 292 |
pub algorithm: CrcFastAlgorithm, |
| 293 |
pub width: u8, |
| 294 |
pub poly: u64, |
| 295 |
pub init: u64, |
| 296 |
pub refin: bool, |
| 297 |
pub refout: bool, |
| 298 |
pub xorout: u64, |
| 299 |
pub check: u64, |
| 300 |
pub key_count: u32, |
| 301 |
pub keys: *const u64, |
| 302 |
} |
| 303 |
|
| 304 |
|
| 305 |
|
| 306 |
fn try_params_from_ffi(value: &CrcFastParams) -> Option<CrcParams> { |
| 307 |
|
| 308 |
if value.keys.is_null() { |
| 309 |
return None; |
| 310 |
} |
| 311 |
|
| 312 |
|
| 313 |
let keys = unsafe { std::slice::from_raw_parts(value.keys, value.key_count as usize) }; |
| 314 |
|
| 315 |
let storage = match value.key_count { |
| 316 |
23 => match keys.try_into() { |
| 317 |
Ok(arr) => crate::CrcKeysStorage::from_keys_fold_256(arr), |
| 318 |
Err(_) => return None, |
| 319 |
}, |
| 320 |
25 => match keys.try_into() { |
| 321 |
Ok(arr) => crate::CrcKeysStorage::from_keys_fold_future_test(arr), |
| 322 |
Err(_) => return None, |
| 323 |
}, |
| 324 |
_ => return None, |
| 325 |
}; |
| 326 |
|
| 327 |
|
| 328 |
let init_algorithm = if value.width == 16 && value.refin { |
| 329 |
(value.init as u16).reverse_bits() as u64 |
| 330 |
} else { |
| 331 |
value.init |
| 332 |
}; |
| 333 |
|
| 334 |
Some(CrcParams { |
| 335 |
algorithm: value.algorithm.into(), |
| 336 |
name: "custom", |
| 337 |
width: value.width, |
| 338 |
poly: value.poly, |
| 339 |
init: value.init, |
| 340 |
init_algorithm, |
| 341 |
refin: value.refin, |
| 342 |
refout: value.refout, |
| 343 |
xorout: value.xorout, |
| 344 |
check: value.check, |
| 345 |
keys: storage, |
| 346 |
}) |
| 347 |
} |
| 348 |
|
| 349 |
|
| 350 |
|
| 351 |
impl From<CrcFastParams> for CrcParams { |
| 352 |
fn from(value: CrcFastParams) -> Self { |
| 353 |
try_params_from_ffi(&value) |
| 354 |
.expect("Invalid CRC parameters: unsupported key count or null pointer") |
| 355 |
} |
| 356 |
} |
| 357 |
|
| 358 |
|
| 359 |
#[allow(deprecated)] |
| 360 |
impl From<CrcParams> for CrcFastParams { |
| 361 |
fn from(params: CrcParams) -> Self { |
| 362 |
|
| 363 |
let (keys_ptr, key_count) = create_stable_key_pointer(¶ms.keys); |
| 364 |
|
| 365 |
CrcFastParams { |
| 366 |
algorithm: match params.algorithm { |
| 367 |
CrcAlgorithm::Crc16Arc => CrcFastAlgorithm::Crc16Arc, |
| 368 |
CrcAlgorithm::Crc16Cdma2000 => CrcFastAlgorithm::Crc16Cdma2000, |
| 369 |
CrcAlgorithm::Crc16Cms => CrcFastAlgorithm::Crc16Cms, |
| 370 |
CrcAlgorithm::Crc16Dds110 => CrcFastAlgorithm::Crc16Dds110, |
| 371 |
CrcAlgorithm::Crc16DectR => CrcFastAlgorithm::Crc16DectR, |
| 372 |
CrcAlgorithm::Crc16DectX => CrcFastAlgorithm::Crc16DectX, |
| 373 |
CrcAlgorithm::Crc16Dnp => CrcFastAlgorithm::Crc16Dnp, |
| 374 |
CrcAlgorithm::Crc16En13757 => CrcFastAlgorithm::Crc16En13757, |
| 375 |
CrcAlgorithm::Crc16Genibus => CrcFastAlgorithm::Crc16Genibus, |
| 376 |
CrcAlgorithm::Crc16Gsm => CrcFastAlgorithm::Crc16Gsm, |
| 377 |
CrcAlgorithm::Crc16Ibm3740 => CrcFastAlgorithm::Crc16Ibm3740, |
| 378 |
CrcAlgorithm::Crc16IbmSdlc => CrcFastAlgorithm::Crc16IbmSdlc, |
| 379 |
CrcAlgorithm::Crc16IsoIec144433A => CrcFastAlgorithm::Crc16IsoIec144433A, |
| 380 |
CrcAlgorithm::Crc16Kermit => CrcFastAlgorithm::Crc16Kermit, |
| 381 |
CrcAlgorithm::Crc16Lj1200 => CrcFastAlgorithm::Crc16Lj1200, |
| 382 |
CrcAlgorithm::Crc16M17 => CrcFastAlgorithm::Crc16M17, |
| 383 |
CrcAlgorithm::Crc16MaximDow => CrcFastAlgorithm::Crc16MaximDow, |
| 384 |
CrcAlgorithm::Crc16Mcrf4xx => CrcFastAlgorithm::Crc16Mcrf4xx, |
| 385 |
CrcAlgorithm::Crc16Modbus => CrcFastAlgorithm::Crc16Modbus, |
| 386 |
CrcAlgorithm::Crc16Nrsc5 => CrcFastAlgorithm::Crc16Nrsc5, |
| 387 |
CrcAlgorithm::Crc16OpensafetyA => CrcFastAlgorithm::Crc16OpensafetyA, |
| 388 |
CrcAlgorithm::Crc16OpensafetyB => CrcFastAlgorithm::Crc16OpensafetyB, |
| 389 |
CrcAlgorithm::Crc16Profibus => CrcFastAlgorithm::Crc16Profibus, |
| 390 |
CrcAlgorithm::Crc16Riello => CrcFastAlgorithm::Crc16Riello, |
| 391 |
CrcAlgorithm::Crc16SpiFujitsu => CrcFastAlgorithm::Crc16SpiFujitsu, |
| 392 |
CrcAlgorithm::Crc16T10Dif => CrcFastAlgorithm::Crc16T10Dif, |
| 393 |
CrcAlgorithm::Crc16Teledisk => CrcFastAlgorithm::Crc16Teledisk, |
| 394 |
CrcAlgorithm::Crc16Tms37157 => CrcFastAlgorithm::Crc16Tms37157, |
| 395 |
CrcAlgorithm::Crc16Umts => CrcFastAlgorithm::Crc16Umts, |
| 396 |
CrcAlgorithm::Crc16Usb => CrcFastAlgorithm::Crc16Usb, |
| 397 |
CrcAlgorithm::Crc16Xmodem => CrcFastAlgorithm::Crc16Xmodem, |
| 398 |
CrcAlgorithm::Crc32Aixm => CrcFastAlgorithm::Crc32Aixm, |
| 399 |
CrcAlgorithm::Crc32Autosar => CrcFastAlgorithm::Crc32Autosar, |
| 400 |
CrcAlgorithm::Crc32Base91D => CrcFastAlgorithm::Crc32Base91D, |
| 401 |
CrcAlgorithm::Crc32Bzip2 => CrcFastAlgorithm::Crc32Bzip2, |
| 402 |
CrcAlgorithm::Crc32CdRomEdc => CrcFastAlgorithm::Crc32CdRomEdc, |
| 403 |
CrcAlgorithm::Crc32Cksum => CrcFastAlgorithm::Crc32Cksum, |
| 404 |
CrcAlgorithm::Crc32Custom => CrcFastAlgorithm::Crc32Custom, |
| 405 |
CrcAlgorithm::Crc32Iscsi => CrcFastAlgorithm::Crc32Iscsi, |
| 406 |
CrcAlgorithm::Crc32IsoHdlc => CrcFastAlgorithm::Crc32IsoHdlc, |
| 407 |
CrcAlgorithm::Crc32Jamcrc => CrcFastAlgorithm::Crc32Jamcrc, |
| 408 |
CrcAlgorithm::Crc32Mef => CrcFastAlgorithm::Crc32Mef, |
| 409 |
CrcAlgorithm::Crc32Mpeg2 => CrcFastAlgorithm::Crc32Mpeg2, |
| 410 |
CrcAlgorithm::Crc32Xfer => CrcFastAlgorithm::Crc32Xfer, |
| 411 |
CrcAlgorithm::CrcCustom => CrcFastAlgorithm::CrcCustom, |
| 412 |
CrcAlgorithm::Crc64Custom => CrcFastAlgorithm::Crc64Custom, |
| 413 |
CrcAlgorithm::Crc64Ecma182 => CrcFastAlgorithm::Crc64Ecma182, |
| 414 |
CrcAlgorithm::Crc64GoIso => CrcFastAlgorithm::Crc64GoIso, |
| 415 |
CrcAlgorithm::Crc64Ms => CrcFastAlgorithm::Crc64Ms, |
| 416 |
CrcAlgorithm::Crc64Nvme => CrcFastAlgorithm::Crc64Nvme, |
| 417 |
CrcAlgorithm::Crc64Redis => CrcFastAlgorithm::Crc64Redis, |
| 418 |
CrcAlgorithm::Crc64We => CrcFastAlgorithm::Crc64We, |
| 419 |
CrcAlgorithm::Crc64Xz => CrcFastAlgorithm::Crc64Xz, |
| 420 |
}, |
| 421 |
width: params.width, |
| 422 |
poly: params.poly, |
| 423 |
init: params.init, |
| 424 |
refin: params.refin, |
| 425 |
refout: params.refout, |
| 426 |
xorout: params.xorout, |
| 427 |
check: params.check, |
| 428 |
key_count, |
| 429 |
keys: keys_ptr, |
| 430 |
} |
| 431 |
} |
| 432 |
} |
| 433 |
|
| 434 |
|
| 435 |
#[no_mangle] |
| 436 |
pub extern "C" fn crc_fast_digest_new(algorithm: CrcFastAlgorithm) -> *mut CrcFastDigestHandle { |
| 437 |
clear_last_error(); |
| 438 |
let digest = Box::new(Digest::new(algorithm.into())); |
| 439 |
let handle = Box::new(CrcFastDigestHandle(Box::into_raw(digest))); |
| 440 |
Box::into_raw(handle) |
| 441 |
} |
| 442 |
|
| 443 |
|
| 444 |
#[no_mangle] |
| 445 |
pub extern "C" fn crc_fast_digest_new_with_init_state( |
| 446 |
algorithm: CrcFastAlgorithm, |
| 447 |
init_state: u64, |
| 448 |
) -> *mut CrcFastDigestHandle { |
| 449 |
clear_last_error(); |
| 450 |
let digest = Box::new(Digest::new_with_init_state(algorithm.into(), init_state)); |
| 451 |
let handle = Box::new(CrcFastDigestHandle(Box::into_raw(digest))); |
| 452 |
Box::into_raw(handle) |
| 453 |
} |
| 454 |
|
| 455 |
|
| 456 |
|
| 457 |
|
| 458 |
#[no_mangle] |
| 459 |
pub extern "C" fn crc_fast_digest_new_with_params( |
| 460 |
params: CrcFastParams, |
| 461 |
) -> *mut CrcFastDigestHandle { |
| 462 |
clear_last_error(); |
| 463 |
match try_params_from_ffi(¶ms) { |
| 464 |
Some(crc_params) => { |
| 465 |
let digest = Box::new(Digest::new_with_params(crc_params)); |
| 466 |
let handle = Box::new(CrcFastDigestHandle(Box::into_raw(digest))); |
| 467 |
Box::into_raw(handle) |
| 468 |
} |
| 469 |
None => { |
| 470 |
|
| 471 |
if params.keys.is_null() { |
| 472 |
set_last_error(CrcFastError::NullPointer); |
| 473 |
} else { |
| 474 |
set_last_error(CrcFastError::InvalidKeyCount); |
| 475 |
} |
| 476 |
std::ptr::null_mut() |
| 477 |
} |
| 478 |
} |
| 479 |
} |
| 480 |
|
| 481 |
|
| 482 |
#[no_mangle] |
| 483 |
pub extern "C" fn crc_fast_digest_update( |
| 484 |
handle: *mut CrcFastDigestHandle, |
| 485 |
data: *const c_char, |
| 486 |
len: usize, |
| 487 |
) { |
| 488 |
if handle.is_null() { |
| 489 |
set_last_error(CrcFastError::NullPointer); |
| 490 |
return; |
| 491 |
} |
| 492 |
if data.is_null() { |
| 493 |
set_last_error(CrcFastError::NullPointer); |
| 494 |
return; |
| 495 |
} |
| 496 |
|
| 497 |
clear_last_error(); |
| 498 |
unsafe { |
| 499 |
let digest = &mut *(*handle).0; |
| 500 |
|
| 501 |
#[allow(clippy::unnecessary_cast)] |
| 502 |
let bytes = slice::from_raw_parts(data as *const u8, len); |
| 503 |
digest.update(bytes); |
| 504 |
} |
| 505 |
} |
| 506 |
|
| 507 |
|
| 508 |
|
| 509 |
#[no_mangle] |
| 510 |
pub extern "C" fn crc_fast_digest_finalize(handle: *mut CrcFastDigestHandle) -> u64 { |
| 511 |
if handle.is_null() { |
| 512 |
set_last_error(CrcFastError::NullPointer); |
| 513 |
return 0; |
| 514 |
} |
| 515 |
|
| 516 |
clear_last_error(); |
| 517 |
unsafe { |
| 518 |
let digest = &*(*handle).0; |
| 519 |
digest.finalize() |
| 520 |
} |
| 521 |
} |
| 522 |
|
| 523 |
|
| 524 |
#[no_mangle] |
| 525 |
pub extern "C" fn crc_fast_digest_free(handle: *mut CrcFastDigestHandle) { |
| 526 |
if handle.is_null() { |
| 527 |
set_last_error(CrcFastError::NullPointer); |
| 528 |
return; |
| 529 |
} |
| 530 |
|
| 531 |
clear_last_error(); |
| 532 |
unsafe { |
| 533 |
let handle = Box::from_raw(handle); |
| 534 |
let _ = Box::from_raw(handle.0); |
| 535 |
} |
| 536 |
} |
| 537 |
|
| 538 |
|
| 539 |
#[no_mangle] |
| 540 |
pub extern "C" fn crc_fast_digest_reset(handle: *mut CrcFastDigestHandle) { |
| 541 |
if handle.is_null() { |
| 542 |
set_last_error(CrcFastError::NullPointer); |
| 543 |
return; |
| 544 |
} |
| 545 |
|
| 546 |
clear_last_error(); |
| 547 |
unsafe { |
| 548 |
let digest = &mut *(*handle).0; |
| 549 |
|
| 550 |
digest.reset(); |
| 551 |
} |
| 552 |
} |
| 553 |
|
| 554 |
|
| 555 |
|
| 556 |
#[no_mangle] |
| 557 |
pub extern "C" fn crc_fast_digest_finalize_reset(handle: *mut CrcFastDigestHandle) -> u64 { |
| 558 |
if handle.is_null() { |
| 559 |
set_last_error(CrcFastError::NullPointer); |
| 560 |
return 0; |
| 561 |
} |
| 562 |
|
| 563 |
clear_last_error(); |
| 564 |
unsafe { |
| 565 |
let digest = &mut *(*handle).0; |
| 566 |
|
| 567 |
digest.finalize_reset() |
| 568 |
} |
| 569 |
} |
| 570 |
|
| 571 |
|
| 572 |
#[no_mangle] |
| 573 |
pub extern "C" fn crc_fast_digest_combine( |
| 574 |
handle1: *mut CrcFastDigestHandle, |
| 575 |
handle2: *mut CrcFastDigestHandle, |
| 576 |
) { |
| 577 |
if handle1.is_null() || handle2.is_null() { |
| 578 |
set_last_error(CrcFastError::NullPointer); |
| 579 |
return; |
| 580 |
} |
| 581 |
|
| 582 |
clear_last_error(); |
| 583 |
unsafe { |
| 584 |
let digest1 = &mut *(*handle1).0; |
| 585 |
let digest2 = &*(*handle2).0; |
| 586 |
digest1.combine(digest2); |
| 587 |
} |
| 588 |
} |
| 589 |
|
| 590 |
|
| 591 |
|
| 592 |
#[no_mangle] |
| 593 |
pub extern "C" fn crc_fast_digest_get_amount(handle: *mut CrcFastDigestHandle) -> u64 { |
| 594 |
if handle.is_null() { |
| 595 |
set_last_error(CrcFastError::NullPointer); |
| 596 |
return 0; |
| 597 |
} |
| 598 |
|
| 599 |
clear_last_error(); |
| 600 |
unsafe { |
| 601 |
let digest = &*(*handle).0; |
| 602 |
digest.get_amount() |
| 603 |
} |
| 604 |
} |
| 605 |
|
| 606 |
|
| 607 |
|
| 608 |
#[no_mangle] |
| 609 |
pub extern "C" fn crc_fast_digest_get_state(handle: *mut CrcFastDigestHandle) -> u64 { |
| 610 |
if handle.is_null() { |
| 611 |
set_last_error(CrcFastError::NullPointer); |
| 612 |
return 0; |
| 613 |
} |
| 614 |
clear_last_error(); |
| 615 |
unsafe { |
| 616 |
let digest = &*(*handle).0; |
| 617 |
digest.get_state() |
| 618 |
} |
| 619 |
} |
| 620 |
|
| 621 |
|
| 622 |
|
| 623 |
#[no_mangle] |
| 624 |
pub extern "C" fn crc_fast_checksum( |
| 625 |
algorithm: CrcFastAlgorithm, |
| 626 |
data: *const c_char, |
| 627 |
len: usize, |
| 628 |
) -> u64 { |
| 629 |
if data.is_null() { |
| 630 |
set_last_error(CrcFastError::NullPointer); |
| 631 |
return 0; |
| 632 |
} |
| 633 |
clear_last_error(); |
| 634 |
unsafe { |
| 635 |
#[allow(clippy::unnecessary_cast)] |
| 636 |
let bytes = slice::from_raw_parts(data as *const u8, len); |
| 637 |
crate::checksum(algorithm.into(), bytes) |
| 638 |
} |
| 639 |
} |
| 640 |
|
| 641 |
|
| 642 |
|
| 643 |
|
| 644 |
#[no_mangle] |
| 645 |
pub extern "C" fn crc_fast_checksum_with_params( |
| 646 |
params: CrcFastParams, |
| 647 |
data: *const c_char, |
| 648 |
len: usize, |
| 649 |
) -> u64 { |
| 650 |
if data.is_null() { |
| 651 |
set_last_error(CrcFastError::NullPointer); |
| 652 |
return 0; |
| 653 |
} |
| 654 |
match try_params_from_ffi(¶ms) { |
| 655 |
Some(crc_params) => { |
| 656 |
clear_last_error(); |
| 657 |
unsafe { |
| 658 |
#[allow(clippy::unnecessary_cast)] |
| 659 |
let bytes = slice::from_raw_parts(data as *const u8, len); |
| 660 |
crate::checksum_with_params(crc_params, bytes) |
| 661 |
} |
| 662 |
} |
| 663 |
None => { |
| 664 |
if params.keys.is_null() { |
| 665 |
set_last_error(CrcFastError::NullPointer); |
| 666 |
} else { |
| 667 |
set_last_error(CrcFastError::InvalidKeyCount); |
| 668 |
} |
| 669 |
0 |
| 670 |
} |
| 671 |
} |
| 672 |
} |
| 673 |
|
| 674 |
|
| 675 |
|
| 676 |
|
| 677 |
#[no_mangle] |
| 678 |
pub extern "C" fn crc_fast_checksum_file( |
| 679 |
algorithm: CrcFastAlgorithm, |
| 680 |
path_ptr: *const u8, |
| 681 |
path_len: usize, |
| 682 |
) -> u64 { |
| 683 |
if path_ptr.is_null() { |
| 684 |
set_last_error(CrcFastError::NullPointer); |
| 685 |
return 0; |
| 686 |
} |
| 687 |
|
| 688 |
unsafe { |
| 689 |
match crate::checksum_file( |
| 690 |
algorithm.into(), |
| 691 |
&convert_to_string(path_ptr, path_len), |
| 692 |
None, |
| 693 |
) { |
| 694 |
Ok(result) => { |
| 695 |
clear_last_error(); |
| 696 |
result |
| 697 |
} |
| 698 |
Err(_) => { |
| 699 |
set_last_error(CrcFastError::IoError); |
| 700 |
0 |
| 701 |
} |
| 702 |
} |
| 703 |
} |
| 704 |
} |
| 705 |
|
| 706 |
|
| 707 |
|
| 708 |
|
| 709 |
#[no_mangle] |
| 710 |
pub extern "C" fn crc_fast_checksum_file_with_params( |
| 711 |
params: CrcFastParams, |
| 712 |
path_ptr: *const u8, |
| 713 |
path_len: usize, |
| 714 |
) -> u64 { |
| 715 |
if path_ptr.is_null() { |
| 716 |
set_last_error(CrcFastError::NullPointer); |
| 717 |
return 0; |
| 718 |
} |
| 719 |
|
| 720 |
match try_params_from_ffi(¶ms) { |
| 721 |
Some(crc_params) => unsafe { |
| 722 |
match crate::checksum_file_with_params( |
| 723 |
crc_params, |
| 724 |
&convert_to_string(path_ptr, path_len), |
| 725 |
None, |
| 726 |
) { |
| 727 |
Ok(result) => { |
| 728 |
clear_last_error(); |
| 729 |
result |
| 730 |
} |
| 731 |
Err(_) => { |
| 732 |
set_last_error(CrcFastError::IoError); |
| 733 |
0 |
| 734 |
} |
| 735 |
} |
| 736 |
}, |
| 737 |
None => { |
| 738 |
if params.keys.is_null() { |
| 739 |
set_last_error(CrcFastError::NullPointer); |
| 740 |
} else { |
| 741 |
set_last_error(CrcFastError::InvalidKeyCount); |
| 742 |
} |
| 743 |
0 |
| 744 |
} |
| 745 |
} |
| 746 |
} |
| 747 |
|
| 748 |
|
| 749 |
#[no_mangle] |
| 750 |
pub extern "C" fn crc_fast_checksum_combine( |
| 751 |
algorithm: CrcFastAlgorithm, |
| 752 |
checksum1: u64, |
| 753 |
checksum2: u64, |
| 754 |
checksum2_len: u64, |
| 755 |
) -> u64 { |
| 756 |
clear_last_error(); |
| 757 |
crate::checksum_combine(algorithm.into(), checksum1, checksum2, checksum2_len) |
| 758 |
} |
| 759 |
|
| 760 |
|
| 761 |
|
| 762 |
|
| 763 |
#[no_mangle] |
| 764 |
pub extern "C" fn crc_fast_checksum_combine_with_params( |
| 765 |
params: CrcFastParams, |
| 766 |
checksum1: u64, |
| 767 |
checksum2: u64, |
| 768 |
checksum2_len: u64, |
| 769 |
) -> u64 { |
| 770 |
match try_params_from_ffi(¶ms) { |
| 771 |
Some(crc_params) => { |
| 772 |
clear_last_error(); |
| 773 |
crate::checksum_combine_with_params(crc_params, checksum1, checksum2, checksum2_len) |
| 774 |
} |
| 775 |
None => { |
| 776 |
if params.keys.is_null() { |
| 777 |
set_last_error(CrcFastError::NullPointer); |
| 778 |
} else { |
| 779 |
set_last_error(CrcFastError::InvalidKeyCount); |
| 780 |
} |
| 781 |
0 |
| 782 |
} |
| 783 |
} |
| 784 |
} |
| 785 |
|
| 786 |
|
| 787 |
|
| 788 |
#[no_mangle] |
| 789 |
pub extern "C" fn crc_fast_get_custom_params( |
| 790 |
name_ptr: *const c_char, |
| 791 |
width: u8, |
| 792 |
poly: u64, |
| 793 |
init: u64, |
| 794 |
reflected: bool, |
| 795 |
xorout: u64, |
| 796 |
check: u64, |
| 797 |
) -> CrcFastParams { |
| 798 |
|
| 799 |
if width != 32 && width != 64 { |
| 800 |
set_last_error(CrcFastError::UnsupportedWidth); |
| 801 |
} else { |
| 802 |
clear_last_error(); |
| 803 |
} |
| 804 |
|
| 805 |
let name = if name_ptr.is_null() { |
| 806 |
"custom" |
| 807 |
} else { |
| 808 |
unsafe { |
| 809 |
match CStr::from_ptr(name_ptr).to_str() { |
| 810 |
Ok(s) => s, |
| 811 |
Err(_) => { |
| 812 |
set_last_error(CrcFastError::InvalidUtf8); |
| 813 |
"custom" |
| 814 |
} |
| 815 |
} |
| 816 |
} |
| 817 |
}; |
| 818 |
|
| 819 |
|
| 820 |
let params = CrcParams::new( |
| 821 |
get_or_leak_string(name), |
| 822 |
width, |
| 823 |
poly, |
| 824 |
init, |
| 825 |
reflected, |
| 826 |
xorout, |
| 827 |
check, |
| 828 |
); |
| 829 |
|
| 830 |
|
| 831 |
let (keys_ptr, key_count) = create_stable_key_pointer(¶ms.keys); |
| 832 |
|
| 833 |
|
| 834 |
CrcFastParams { |
| 835 |
algorithm: CrcFastAlgorithm::CrcCustom, |
| 836 |
width: params.width, |
| 837 |
poly: params.poly, |
| 838 |
init: params.init, |
| 839 |
refin: params.refin, |
| 840 |
refout: params.refout, |
| 841 |
xorout: params.xorout, |
| 842 |
check: params.check, |
| 843 |
key_count, |
| 844 |
keys: keys_ptr, |
| 845 |
} |
| 846 |
} |
| 847 |
|
| 848 |
|
| 849 |
|
| 850 |
|
| 851 |
#[no_mangle] |
| 852 |
pub extern "C" fn crc_fast_get_calculator_target(algorithm: CrcFastAlgorithm) -> *const c_char { |
| 853 |
let target = get_calculator_target(algorithm.into()); |
| 854 |
|
| 855 |
match std::ffi::CString::new(target) { |
| 856 |
Ok(s) => { |
| 857 |
clear_last_error(); |
| 858 |
s.into_raw() |
| 859 |
} |
| 860 |
Err(_) => { |
| 861 |
set_last_error(CrcFastError::StringConversionError); |
| 862 |
std::ptr::null_mut() |
| 863 |
} |
| 864 |
} |
| 865 |
} |
| 866 |
|
| 867 |
|
| 868 |
|
| 869 |
#[no_mangle] |
| 870 |
pub extern "C" fn crc_fast_get_version() -> *const c_char { |
| 871 |
const VERSION: &CStr = |
| 872 |
match CStr::from_bytes_with_nul(concat!(env!("CARGO_PKG_VERSION"), "\0").as_bytes()) { |
| 873 |
Ok(version) => version, |
| 874 |
|
| 875 |
Err(_) => c"unknown", |
| 876 |
}; |
| 877 |
|
| 878 |
VERSION.as_ptr() |
| 879 |
} |
| 880 |
|
| 881 |
|
| 882 |
|
| 883 |
|
| 884 |
|
| 885 |
|
| 886 |
|
| 887 |
#[no_mangle] |
| 888 |
pub extern "C" fn crc_fast_crc32_iscsi(data: *const c_char, len: usize) -> u32 { |
| 889 |
if data.is_null() { |
| 890 |
set_last_error(CrcFastError::NullPointer); |
| 891 |
return 0; |
| 892 |
} |
| 893 |
clear_last_error(); |
| 894 |
unsafe { |
| 895 |
#[allow(clippy::unnecessary_cast)] |
| 896 |
let bytes = slice::from_raw_parts(data as *const u8, len); |
| 897 |
crate::crc32_iscsi(bytes) |
| 898 |
} |
| 899 |
} |
| 900 |
|
| 901 |
|
| 902 |
|
| 903 |
|
| 904 |
|
| 905 |
|
| 906 |
|
| 907 |
#[no_mangle] |
| 908 |
pub extern "C" fn crc_fast_crc32_iso_hdlc(data: *const c_char, len: usize) -> u32 { |
| 909 |
if data.is_null() { |
| 910 |
set_last_error(CrcFastError::NullPointer); |
| 911 |
return 0; |
| 912 |
} |
| 913 |
clear_last_error(); |
| 914 |
unsafe { |
| 915 |
#[allow(clippy::unnecessary_cast)] |
| 916 |
let bytes = slice::from_raw_parts(data as *const u8, len); |
| 917 |
crate::crc32_iso_hdlc(bytes) |
| 918 |
} |
| 919 |
} |
| 920 |
|
| 921 |
|
| 922 |
|
| 923 |
|
| 924 |
|
| 925 |
|
| 926 |
#[no_mangle] |
| 927 |
pub extern "C" fn crc_fast_crc64_nvme(data: *const c_char, len: usize) -> u64 { |
| 928 |
if data.is_null() { |
| 929 |
set_last_error(CrcFastError::NullPointer); |
| 930 |
return 0; |
| 931 |
} |
| 932 |
clear_last_error(); |
| 933 |
unsafe { |
| 934 |
#[allow(clippy::unnecessary_cast)] |
| 935 |
let bytes = slice::from_raw_parts(data as *const u8, len); |
| 936 |
crate::crc64_nvme(bytes) |
| 937 |
} |
| 938 |
} |
| 939 |
|
| 940 |
unsafe fn convert_to_string(data: *const u8, len: usize) -> String { |
| 941 |
if data.is_null() { |
| 942 |
return String::new(); |
| 943 |
} |
| 944 |
|
| 945 |
|
| 946 |
match std::str::from_utf8(slice::from_raw_parts(data, len)) { |
| 947 |
Ok(s) => s.to_string(), |
| 948 |
Err(_) => String::new(), |
| 949 |
} |
| 950 |
} |
| 951 |
|
| 952 |
fn get_or_leak_string(s: &str) -> &'static str { |
| 953 |
let cache = STRING_CACHE.get_or_init(|| Mutex::new(HashSet::new())); |
| 954 |
let mut cache = cache.lock().unwrap(); |
| 955 |
|
| 956 |
|
| 957 |
if let Some(&cached) = cache.get(s) { |
| 958 |
return cached; |
| 959 |
} |
| 960 |
|
| 961 |
|
| 962 |
let leaked: &'static str = Box::leak(s.to_string().into_boxed_str()); |
| 963 |
cache.insert(leaked); |
| 964 |
leaked |
| 965 |
} |