141 lines
4.4 KiB
HTML
141 lines
4.4 KiB
HTML
<html data-theme="light">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<link rel="stylesheet" href="pico.min.css" />
|
|
</head>
|
|
<body>
|
|
<main class="container">
|
|
<form id="form">
|
|
<fieldset role="group">
|
|
<input type="text" name="thing" placeholder="Enter barcode here..." />
|
|
<button type="submit" disabled>Decode</button>
|
|
</fieldset>
|
|
<small><a href="#" id="example">Try an example</a></small>
|
|
</form>
|
|
|
|
<pre id="result"></pre>
|
|
</main>
|
|
|
|
<footer class="container">
|
|
<small>
|
|
<a
|
|
href="https://github.com/cjdenio/usps-barcode-decoder"
|
|
class="secondary"
|
|
>[source on GitHub]</a
|
|
>
|
|
</small>
|
|
</footer>
|
|
|
|
<script>
|
|
WebAssembly.instantiateStreaming(fetch("imb.wasm")).then(
|
|
({ instance }) => {
|
|
const { decodeStringWasm, malloc, free, memory } = instance.exports;
|
|
|
|
function allocString(str) {
|
|
str += "\0"; // add null terminator
|
|
|
|
const encoder = new TextEncoder();
|
|
const encoded = encoder.encode(str);
|
|
|
|
const ptr = instance.exports.malloc(encoded.length);
|
|
|
|
const mem = new Uint8Array(instance.exports.memory.buffer);
|
|
|
|
for (let i = 0; i < encoded.length; i++) {
|
|
mem[ptr + i] = encoded[i];
|
|
}
|
|
|
|
return [ptr, encoded.length];
|
|
}
|
|
|
|
function decodeBarcode(str) {
|
|
if (!/^[adft]{65}$/i.test(str)) throw new Error("invalid string");
|
|
|
|
const [string, stringLen] = allocString(str);
|
|
|
|
const result = decodeStringWasm(string);
|
|
|
|
free(string, stringLen);
|
|
|
|
if (result == 0) throw new Error("invalid character");
|
|
if (result == 1) throw new Error("decoding error");
|
|
if (result == 2) throw new Error("unknown error");
|
|
if (result == 3) throw new Error("invalid checksum");
|
|
|
|
const resultString = new TextDecoder().decode(
|
|
new Uint8Array(memory.buffer).subarray(result, result + 31)
|
|
);
|
|
|
|
free(result, 31);
|
|
|
|
return parseDecoded(resultString);
|
|
}
|
|
|
|
function parseDecoded(decoded) {
|
|
const tracking_code = decoded.substring(0, 20);
|
|
const routing_code = decoded.substring(20).replace(/[^0-9]/g, "");
|
|
|
|
let zip, mailerId, serialNumber;
|
|
|
|
if (routing_code.length == 11) {
|
|
zip = `${routing_code.substring(0, 5)}-${routing_code.substring(
|
|
5,
|
|
9
|
|
)}(${routing_code.substring(9, 11)})`;
|
|
} else if (routing_code.length == 9) {
|
|
zip = `${routing_code.substring(0, 5)}-${routing_code.substring(
|
|
5,
|
|
9
|
|
)}`;
|
|
} else {
|
|
zip = routing_code;
|
|
}
|
|
|
|
if (tracking_code[5] == 9) {
|
|
mailerId = tracking_code.substring(5, 5 + 9);
|
|
serialNumber = tracking_code.substring(14, 14 + 6);
|
|
} else {
|
|
mailerId = tracking_code.substring(5, 5 + 6);
|
|
serialNumber = tracking_code.substring(11, 11 + 9);
|
|
}
|
|
|
|
return {
|
|
tracking_code: {
|
|
barcodeId: tracking_code.substring(0, 2),
|
|
serviceType: tracking_code.substring(2, 5),
|
|
mailerId,
|
|
serialNumber,
|
|
},
|
|
zip,
|
|
};
|
|
}
|
|
|
|
document.getElementById("form").addEventListener("submit", (e) => {
|
|
e.preventDefault();
|
|
try {
|
|
const result = decodeBarcode(e.target.thing.value);
|
|
document.getElementById("result").innerText = JSON.stringify(
|
|
result,
|
|
null,
|
|
2
|
|
);
|
|
} catch (e) {
|
|
document.getElementById("result").innerText = e;
|
|
}
|
|
});
|
|
|
|
document.querySelector("button[type=submit]").disabled = false;
|
|
|
|
document.getElementById("example").addEventListener("click", (e) => {
|
|
e.preventDefault();
|
|
document.querySelector("form input[name=thing]").value =
|
|
"TATAFFADTTFDDFTFAFDFTFFATTFDDFTDFTDDTADAAFTTFAAADFFFDTDTTDFATDDDT";
|
|
document.getElementById("form").requestSubmit();
|
|
});
|
|
}
|
|
);
|
|
</script>
|
|
</body>
|
|
</html>
|