fix(capture): make printer-byte parsing binary-safe
Some checks failed
Desktop Release / Bootstrap updater signing key (push) Has been cancelled
Desktop Release / Windows x64 NSIS (push) Has been cancelled
Desktop Release / Linux x64 DEB + AppImage (push) Has been cancelled
Desktop Release / Publish public desktop release (push) Has been cancelled
Some checks failed
Desktop Release / Bootstrap updater signing key (push) Has been cancelled
Desktop Release / Windows x64 NSIS (push) Has been cancelled
Desktop Release / Linux x64 DEB + AppImage (push) Has been cancelled
Desktop Release / Publish public desktop release (push) Has been cancelled
This commit is contained in:
parent
2cdf909c36
commit
8c42f9cb9f
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@fieldlens/print",
|
"name": "@fieldlens/print",
|
||||||
"version": "0.1.4",
|
"version": "0.1.5",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "fieldlens-print"
|
name = "fieldlens-print"
|
||||||
version = "0.1.4"
|
version = "0.1.5"
|
||||||
description = "FieldLens print-stream barcode capture companion"
|
description = "FieldLens print-stream barcode capture companion"
|
||||||
authors = ["Arrowstack"]
|
authors = ["Arrowstack"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|||||||
@ -391,7 +391,14 @@ fn process_payload(
|
|||||||
error: Option<String>,
|
error: Option<String>,
|
||||||
) {
|
) {
|
||||||
let id = Uuid::new_v4().to_string();
|
let id = Uuid::new_v4().to_string();
|
||||||
let barcodes = extract_barcodes(&bytes);
|
let (barcodes, parse_error) = match std::panic::catch_unwind(|| extract_barcodes(&bytes)) {
|
||||||
|
Ok(found) => (found, None),
|
||||||
|
Err(_) => (
|
||||||
|
Vec::new(),
|
||||||
|
Some("barcode parser failed; print bytes were still captured and forwarded".to_string()),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
let error = error.or(parse_error);
|
||||||
|
|
||||||
for barcode in &barcodes {
|
for barcode in &barcodes {
|
||||||
state.queue_scan(
|
state.queue_scan(
|
||||||
|
|||||||
@ -1,12 +1,14 @@
|
|||||||
use crate::model::DecodedBarcode;
|
use crate::model::DecodedBarcode;
|
||||||
|
|
||||||
pub fn extract_barcodes(bytes: &[u8]) -> Vec<DecodedBarcode> {
|
pub fn extract_barcodes(bytes: &[u8]) -> Vec<DecodedBarcode> {
|
||||||
let text = String::from_utf8_lossy(bytes);
|
extract_from_zpl_bytes(bytes)
|
||||||
extract_from_zpl(&text)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn extract_from_zpl(input: &str) -> Vec<DecodedBarcode> {
|
pub fn extract_from_zpl(input: &str) -> Vec<DecodedBarcode> {
|
||||||
let bytes = input.as_bytes();
|
extract_from_zpl_bytes(input.as_bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extract_from_zpl_bytes(bytes: &[u8]) -> Vec<DecodedBarcode> {
|
||||||
let mut index = 0usize;
|
let mut index = 0usize;
|
||||||
let mut pending_format: Option<String> = None;
|
let mut pending_format: Option<String> = None;
|
||||||
let mut barcodes = Vec::new();
|
let mut barcodes = Vec::new();
|
||||||
@ -18,7 +20,7 @@ pub fn extract_from_zpl(input: &str) -> Vec<DecodedBarcode> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let command_start = index;
|
let command_start = index;
|
||||||
let command = &input[index + 1..index + 3];
|
let command = &bytes[index + 1..index + 3];
|
||||||
index += 3;
|
index += 3;
|
||||||
|
|
||||||
if let Some(format) = barcode_format(command) {
|
if let Some(format) = barcode_format(command) {
|
||||||
@ -26,14 +28,13 @@ pub fn extract_from_zpl(input: &str) -> Vec<DecodedBarcode> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if command == "FD" {
|
if command == b"FD" {
|
||||||
let end = input[index..]
|
let end = find_bytes(&bytes[index..], b"^FS")
|
||||||
.find("^FS")
|
|
||||||
.map(|offset| index + offset)
|
.map(|offset| index + offset)
|
||||||
.unwrap_or(input.len());
|
.unwrap_or(bytes.len());
|
||||||
if let Some(format) = pending_format.take() {
|
if let Some(format) = pending_format.take() {
|
||||||
let raw = input[index..end].trim();
|
let raw = String::from_utf8_lossy(&bytes[index..end]);
|
||||||
let value = normalize_field_data(raw);
|
let value = normalize_field_data(raw.trim());
|
||||||
if !value.is_empty() {
|
if !value.is_empty() {
|
||||||
barcodes.push(DecodedBarcode { format, value });
|
barcodes.push(DecodedBarcode { format, value });
|
||||||
}
|
}
|
||||||
@ -42,7 +43,7 @@ pub fn extract_from_zpl(input: &str) -> Vec<DecodedBarcode> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if command == "FS" || command == "XZ" {
|
if command == b"FS" || command == b"XZ" {
|
||||||
pending_format = None;
|
pending_format = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,23 +55,30 @@ pub fn extract_from_zpl(input: &str) -> Vec<DecodedBarcode> {
|
|||||||
barcodes
|
barcodes
|
||||||
}
|
}
|
||||||
|
|
||||||
fn barcode_format(command: &str) -> Option<&'static str> {
|
fn barcode_format(command: &[u8]) -> Option<&'static str> {
|
||||||
match command {
|
match command {
|
||||||
"BC" => Some("CODE_128"),
|
b"BC" => Some("CODE_128"),
|
||||||
"B3" => Some("CODE_39"),
|
b"B3" => Some("CODE_39"),
|
||||||
"BE" => Some("EAN_13"),
|
b"BE" => Some("EAN_13"),
|
||||||
"B8" => Some("EAN_8"),
|
b"B8" => Some("EAN_8"),
|
||||||
"BU" => Some("UPC_A"),
|
b"BU" => Some("UPC_A"),
|
||||||
"B9" => Some("UPC_E"),
|
b"B9" => Some("UPC_E"),
|
||||||
"B2" => Some("ITF"),
|
b"B2" => Some("ITF"),
|
||||||
"BQ" => Some("QR_CODE"),
|
b"BQ" => Some("QR_CODE"),
|
||||||
"BX" => Some("DATA_MATRIX"),
|
b"BX" => Some("DATA_MATRIX"),
|
||||||
"B7" => Some("PDF_417"),
|
b"B7" => Some("PDF_417"),
|
||||||
"BA" => Some("CODE_93"),
|
b"BA" => Some("CODE_93"),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn find_bytes(haystack: &[u8], needle: &[u8]) -> Option<usize> {
|
||||||
|
if needle.is_empty() {
|
||||||
|
return Some(0);
|
||||||
|
}
|
||||||
|
haystack.windows(needle.len()).position(|window| window == needle)
|
||||||
|
}
|
||||||
|
|
||||||
fn normalize_field_data(raw: &str) -> String {
|
fn normalize_field_data(raw: &str) -> String {
|
||||||
let mut value = raw.to_string();
|
let mut value = raw.to_string();
|
||||||
|
|
||||||
@ -124,4 +132,15 @@ mod tests {
|
|||||||
let zpl = "^XA^FO10,10^A0N,30,30^FDNOT-A-BARCODE^FS^XZ";
|
let zpl = "^XA^FO10,10^A0N,30,30^FDNOT-A-BARCODE^FS^XZ";
|
||||||
assert!(extract_from_zpl(zpl).is_empty());
|
assert!(extract_from_zpl(zpl).is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn arbitrary_binary_printer_data_never_panics() {
|
||||||
|
let payload = [
|
||||||
|
0x1b, b'@', 0xff, 0x00, 0xfe, b'^', 0xff, 0xfd, 0x1b, b'(', b'G',
|
||||||
|
0x10, 0x00, 0x80, 0x81, 0x82, b'^', b'F', b'D', 0xf0, 0x9f, 0x92,
|
||||||
|
0xa9, b'^', b'F', b'S',
|
||||||
|
];
|
||||||
|
let found = extract_barcodes(&payload);
|
||||||
|
assert!(found.is_empty());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://schema.tauri.app/config/2",
|
"$schema": "https://schema.tauri.app/config/2",
|
||||||
"productName": "FieldLens Print",
|
"productName": "FieldLens Print",
|
||||||
"version": "0.1.4",
|
"version": "0.1.5",
|
||||||
"identifier": "dev.arrowstack.fieldlens.print",
|
"identifier": "dev.arrowstack.fieldlens.print",
|
||||||
"build": {
|
"build": {
|
||||||
"beforeDevCommand": "npm run dev",
|
"beforeDevCommand": "npm run dev",
|
||||||
|
|||||||
@ -85,7 +85,7 @@ let config: AppConfig
|
|||||||
let jobs: Job[] = []
|
let jobs: Job[] = []
|
||||||
let status: Status
|
let status: Status
|
||||||
let loginTimer: number | undefined
|
let loginTimer: number | undefined
|
||||||
let currentVersion = '0.1.4'
|
let currentVersion = '0.1.5'
|
||||||
let bundleType: BundleType | null = null
|
let bundleType: BundleType | null = null
|
||||||
let availableUpdate: Update | null = null
|
let availableUpdate: Update | null = null
|
||||||
let availableManualUpdate: ManualUpdate | null = null
|
let availableManualUpdate: ManualUpdate | null = null
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user