1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
use std::ffi;
use std::ptr;
use std::slice;
#[link(name = "iec16022")]
unsafe extern "C" {
/// encoding function
///
/// Returns the grid (malloced) containing the matrix. L corner at 0,0.
/// Takes suggested size in `w_ptr`, `h_ptr`, or 0,0. Fills in actual size.
/// Takes `barcodelen` and `barcode` to be encoded
/// Note, if `encodingptr` is null, then fills with auto picked (malloced)
/// encoding.
/// If `lenp` not null, then the length of encoded data before any final unlatch
/// or pad is stored.
/// If `maxp` not null, then the max storage of this size code is stored
/// If `eccp` not null, then the number of ecc bytes used in this size is stored
/// Returns 0 on error (writes to stderr with details).
fn iec16022ecc200f(
w_ptr: *mut ffi::c_int,
h_ptr: *mut ffi::c_int,
encodingptr: *mut *mut ffi::c_char,
barcodelen: ffi::c_int,
barcode: *const ffi::c_uchar,
lenp: *mut ffi::c_int,
maxp: *mut ffi::c_int,
eccp: *mut ffi::c_int,
flags: ffi::c_int,
) -> *mut ffi::c_uchar;
}
#[derive(PartialEq, Eq, Debug)]
pub enum EncodeError {
DataTooLong,
Encoder,
DimensionsTooLarge,
}
#[derive(Debug)]
pub struct DataMatrix {
width: usize,
height: usize,
grid_ptr: *mut ffi::c_uchar,
}
impl DataMatrix {
/// Encodes data as a data matrix
pub fn encode(data: &[u8]) -> Result<Self, EncodeError> {
let mut width = 0;
let mut height = 0;
let data_ptr = data.as_ptr();
let data_len = data
.len()
.try_into()
.map_err(|_| EncodeError::DataTooLong)?;
// SAFETY: ffi
let grid_ptr = unsafe {
iec16022ecc200f(
&raw mut width,
&raw mut height,
ptr::null_mut(),
data_len,
data_ptr,
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
0,
)
};
if grid_ptr.is_null() || width == 0 || height == 0 {
Err(EncodeError::Encoder)
} else {
Ok(Self {
width: width
.try_into()
.map_err(|_| EncodeError::DimensionsTooLarge)?,
height: height
.try_into()
.map_err(|_| EncodeError::DimensionsTooLarge)?,
grid_ptr,
})
}
}
#[must_use]
pub const fn width(&self) -> usize {
self.width
}
#[must_use]
pub const fn height(&self) -> usize {
self.height
}
#[must_use]
const fn grid(&self) -> &[bool] {
// SAFETY: returned grid consists only contains values 0 and 1
unsafe { slice::from_raw_parts(self.grid_ptr as *const bool, self.width * self.height) }
}
#[must_use]
pub const fn get(&self, row: usize, col: usize) -> bool {
assert!(row < self.height(), "row index out of bounds");
assert!(col < self.width(), "col index out of bounds");
let idx = row * self.width + col;
self.grid()[idx]
}
}
impl Drop for DataMatrix {
fn drop(&mut self) {
// SAFETY: self.ptr malloc'ed in ffi
unsafe { libc::free(self.grid_ptr.cast()) };
}
}
|