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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
// Author: cirakg & claude ai
// Summary: Code 128 encoder (sets B and C) with zxing's look-ahead rules for when to switch to digit pairs.
//
// Accepts printable ASCII (32-126). Set C packs two digits per symbol; the
// encoder starts in C for leading digit pairs and switches to C for runs
// of at least four digits, choosing the switch point so an odd digit is
// encoded in B first (the rules of zxing's Code128Writer). zxing-cpp 3,
// the test reference, writes through zint, which breaks ties between equally
// short encodings differently; the tests require the same length (it was
// equal for 5,000 random strings) and decoding. GS1-128 (FNC1) is deferred.
import Toybox.Lang;
module Code128 {
// Bar/space widths of symbol values 0-105 (6 elements, starting with a
// bar); STOP (106) has 7 elements.
const PATTERNS = [
"212222", "222122", "222221", "121223", "121322", "131222", "122213", "122312", "132212", "221213",
"221312", "231212", "112232", "122132", "122231", "113222", "123122", "123221", "223211", "221132",
"221231", "213212", "223112", "312131", "311222", "321122", "321221", "312212", "322112", "322211",
"212123", "212321", "232121", "111323", "131123", "131321", "112313", "132113", "132311", "211313",
"231113", "231311", "112133", "112331", "132131", "113123", "113321", "133121", "313121", "211331",
"231131", "213113", "213311", "213131", "311123", "311321", "331121", "312113", "312311", "332111",
"314111", "221411", "431111", "111224", "111422", "121124", "121421", "141122", "141221", "112214",
"112412", "122114", "122411", "142112", "142211", "241211", "221114", "413111", "241112", "134111",
"111242", "121142", "121241", "114212", "124112", "124211", "411212", "421112", "421211", "212141",
"214121", "412121", "111143", "111341", "131141", "114113", "114311", "411113", "411311", "113141",
"114131", "311141", "411131", "211412", "211214", "211232", "2331112"
]; // lint: allow-literal (published Code 128 symbol widths)
const CODE_C = 99;
const CODE_B = 100;
const START_B = 104;
const START_C = 105;
const STOP = 106;
// Look-ahead classes.
const UNCODABLE = 0; // not a digit, or the end
const ONE_DIGIT = 1;
const TWO_DIGITS = 2;
function encode(text as String) as Codes.LinearCode or Codes.CodeError {
var chars = text.toCharArray();
if (chars.size() == 0) {
return new Codes.CodeError("Code 128 needs some text");
}
for (var i = 0; i < chars.size(); i++) {
var c = chars[i].toNumber();
if (c < 32 || c > 126) {
return new Codes.CodeError("Code 128: '" + chars[i] + "' (position " + (i + 1) + ") is not a printable ASCII character");
}
}
var values = [] as Array<Number>;
var codeSet = 0;
var position = 0;
while (position < chars.size()) {
var next = choose(chars, position, codeSet);
var value = 0;
if (next == codeSet) {
if (codeSet == CODE_C) {
value = (chars[position].toNumber() - 48) * 10 + chars[position + 1].toNumber() - 48;
position += 2;
} else {
value = chars[position].toNumber() - 32;
position += 1;
}
} else {
value = codeSet == 0 ? (next == CODE_C ? START_C : START_B) : next;
codeSet = next;
}
values.add(value);
}
// Checksum: start value plus each following value times its position.
var sum = values[0];
for (var i = 1; i < values.size(); i++) {
sum += values[i] * i;
}
values.add(sum % 103);
values.add(STOP);
var m = []b;
for (var i = 0; i < values.size(); i++) {
Codes.addRuns(m, widths(PATTERNS[values[i]] as String), true);
}
return new Codes.LinearCode(m, text);
}
function widths(pattern as String) as Array<Number> {
var chars = pattern.toCharArray();
var out = [] as Array<Number>;
for (var i = 0; i < chars.size(); i++) {
out.add(chars[i].toNumber() - 48);
}
return out;
}
function cType(chars as Array<Char>, start as Number) as Number {
if (start >= chars.size() || !isDigit(chars[start])) {
return UNCODABLE;
}
if (start + 1 >= chars.size() || !isDigit(chars[start + 1])) {
return ONE_DIGIT;
}
return TWO_DIGITS;
}
function isDigit(c as Char) as Boolean {
return c >= '0' && c <= '9';
}
// The code set for the symbol at `start` (zxing's chooseCode, without
// set A and FNC1, which this encoder doesn't use).
function choose(chars as Array<Char>, start as Number, oldCode as Number) as Number {
var lookahead = cType(chars, start);
if (lookahead != TWO_DIGITS) {
return CODE_B;
}
if (oldCode == CODE_C) {
return CODE_C;
}
if (oldCode == CODE_B) {
lookahead = cType(chars, start + 2);
if (lookahead != TWO_DIGITS) {
return CODE_B; // fewer than 4 digits: not worth switching
}
var index = start + 4;
lookahead = cType(chars, index);
while (lookahead == TWO_DIGITS) {
index += 2;
lookahead = cType(chars, index);
}
// An odd number of digits: encode one in B, then switch.
return lookahead == ONE_DIGIT ? CODE_B : CODE_C;
}
return CODE_C; // the first symbol: start in C for a digit pair
}
}
|