1 | { lbc_plessey - Handles plessey bar codes
|
---|
2 |
|
---|
3 | Based on Zint (done by Robin Stuart and the Zint team)
|
---|
4 | http://github.com/zint/zint
|
---|
5 | and Pascal adaption by TheUnknownOnes
|
---|
6 | http://theunknownones.net
|
---|
7 |
|
---|
8 | Refactoring: W.Pamler
|
---|
9 |
|
---|
10 | The results were checked against https://www.free-barcode-generator.net/msi/
|
---|
11 | }
|
---|
12 |
|
---|
13 | unit lbc_plessey;
|
---|
14 |
|
---|
15 | {$mode objfpc}{$H+}
|
---|
16 |
|
---|
17 | interface
|
---|
18 |
|
---|
19 | uses
|
---|
20 | SysUtils, zint;
|
---|
21 |
|
---|
22 | function plessey(ASymbol: PZintSymbol; const ASource: String): Integer;
|
---|
23 | function msi_plessey(ASymbol: PZintSymbol; const ASource: String): Integer;
|
---|
24 |
|
---|
25 | implementation
|
---|
26 |
|
---|
27 | uses
|
---|
28 | lbc_helper;
|
---|
29 |
|
---|
30 | const
|
---|
31 | SSET = '0123456789ABCDEF';
|
---|
32 |
|
---|
33 | // Idea: These are the bits in a nibble: 13 = 0, 31 = 1, LSB at left
|
---|
34 | PlesseyTable: array[0..15] of String = (
|
---|
35 | '13131313', '31131313', '13311313', '31311313', '13133113',
|
---|
36 | '31133113', '13313113', '31313113', '13131331', '31131331',
|
---|
37 | '13311331', '31311331', '13133131', '31133131', '13313131',
|
---|
38 | '31313131'
|
---|
39 | );
|
---|
40 |
|
---|
41 | MSITable: array[0..9] of String = (
|
---|
42 | '12121212', '12121221', '12122112', '12122121', '12211212',
|
---|
43 | '12211221', '12212112', '12212121', '21121212', '21121221'
|
---|
44 | );
|
---|
45 |
|
---|
46 |
|
---|
47 | {-------------------------------------------------------------------------------
|
---|
48 | Not MSI/Plessey, but the older Plessey standard
|
---|
49 | -------------------------------------------------------------------------------}
|
---|
50 | function CheckSum_Plessey(ASource: String): String;
|
---|
51 | const
|
---|
52 | grid: array[0..8] of Byte = (1,1,1,1,0,1,0,0,1);
|
---|
53 | var
|
---|
54 | i, j, check: Integer;
|
---|
55 | checkptr: array of byte = nil;
|
---|
56 | begin
|
---|
57 | SetLength(checkptr, Length(ASource)* 4 + 8);
|
---|
58 |
|
---|
59 | for i := 0 to Length(ASource) - 1 do
|
---|
60 | begin
|
---|
61 | j := i+1;
|
---|
62 | check := pos(ASource[j], SSET) - 1;
|
---|
63 | checkptr[4*i] := check and 1;
|
---|
64 | checkptr[4*i+1] := (check shr 1) and 1;
|
---|
65 | checkptr[4*i+2] := (check shr 2) and 1;
|
---|
66 | checkptr[4*i+3] := (check shr 3) and 1;
|
---|
67 | end;
|
---|
68 |
|
---|
69 | // CRC check digit code adapted from code by Leonid A. Broukhis
|
---|
70 | // used in GNU Barcode
|
---|
71 | for i := 0 to 4 * Length(ASource) - 1 do
|
---|
72 | begin
|
---|
73 | if (checkptr[i] <> 0) then
|
---|
74 | for j := 0 to 8 do
|
---|
75 | checkptr[i+j] := checkptr[i+j] xor grid[j];
|
---|
76 | end;
|
---|
77 |
|
---|
78 | check := 0;
|
---|
79 | for i := 0 to 7 do
|
---|
80 | if checkptr[Length(ASource) * 4 + i] = 1 then
|
---|
81 | check := check or (1 shl i);
|
---|
82 |
|
---|
83 | Result := SSET[succ(check and $0F)] + SSET[succ((check and $F0) shr 4)];
|
---|
84 | end;
|
---|
85 |
|
---|
86 | function plessey(ASymbol: PZintSymbol; const ASource: String): Integer;
|
---|
87 | begin
|
---|
88 | Result := basic_encoder(ASymbol, ASource,
|
---|
89 | 65, SSET, '31311331', PlesseyTable, '331311313', @CheckSum_Plessey, false);
|
---|
90 | if Result = 0 then
|
---|
91 | ASymbol^.SetText(ASource);
|
---|
92 | end;
|
---|
93 |
|
---|
94 |
|
---|
95 | {-------------------------------------------------------------------------------
|
---|
96 | MSI Plessey Modulo 10 and Modulo 11 check digit calculation routines
|
---|
97 |
|
---|
98 | Algorithm from Barcode Island, http://www.barcodeisland.com/
|
---|
99 | (wp: page no longer available)
|
---|
100 | -------------------------------------------------------------------------------}
|
---|
101 | function PartialString(ASource: String; OddIndices: boolean): String;
|
---|
102 | var
|
---|
103 | i: Integer;
|
---|
104 | begin
|
---|
105 | Result := '';
|
---|
106 | if OddIndices then i := 1 else i := 2;
|
---|
107 | while i <= Length(ASource) do
|
---|
108 | begin
|
---|
109 | Result := Result + ASource[i];
|
---|
110 | inc(i, 2);
|
---|
111 | end;
|
---|
112 | end;
|
---|
113 |
|
---|
114 | function SumOfDigits(s: String): Integer;
|
---|
115 | var
|
---|
116 | i: Integer;
|
---|
117 | begin
|
---|
118 | Result := 0;
|
---|
119 | for i := 1 to Length(s) do
|
---|
120 | Result := Result + StrToInt(s[i]);
|
---|
121 | end;
|
---|
122 |
|
---|
123 | function SumOfDigits(s: String; OddIndices: Boolean): Integer;
|
---|
124 | var
|
---|
125 | i: Integer;
|
---|
126 | begin
|
---|
127 | Result := 0;
|
---|
128 | if OddIndices then i := 1 else i := 2;
|
---|
129 | while i <= Length(s) do
|
---|
130 | begin
|
---|
131 | Result := Result + StrToInt(s[i]);
|
---|
132 | inc(i, 2);
|
---|
133 | end;
|
---|
134 | end;
|
---|
135 |
|
---|
136 | { Calculation of a mod 10 check digit.
|
---|
137 | Algorithm from Barcode Island, http://www.barcodeisland.com/
|
---|
138 | (wp: page no longer available) }
|
---|
139 | function CheckSum_Plessey_Mod10(ASource: String): String;
|
---|
140 | var
|
---|
141 | s: String;
|
---|
142 | sum: Integer;
|
---|
143 | check: Integer;
|
---|
144 | begin
|
---|
145 | s := PartialString(ASource, odd(Length(ASource)));
|
---|
146 | s := IntToStr(StrToInt(s)*2);
|
---|
147 | sum := SumOfDigits(s) + SumOfDigits(ASource, not odd(Length(ASource)));
|
---|
148 | check := 10 - sum mod 10;
|
---|
149 | if check = 10 then check := 0;
|
---|
150 | Result := IntToStr(check);
|
---|
151 | end;
|
---|
152 |
|
---|
153 | { Calculation of two mod 10 check digits.
|
---|
154 | Based on above Barcode Island code. }
|
---|
155 | function CheckSum_Plessey_Mod10_Mod10(ASource: String): String;
|
---|
156 | var
|
---|
157 | s: String;
|
---|
158 | sum: Integer;
|
---|
159 | check: Integer;
|
---|
160 | begin
|
---|
161 | // Calculate first check digit
|
---|
162 | Result := CheckSum_Plessey_Mod10(ASource);
|
---|
163 |
|
---|
164 | // Calculate second check digit
|
---|
165 | s := PartialString(ASource, not odd(Length(ASource))) + Result;
|
---|
166 | s := IntToStr(StrToInt(s)*2);
|
---|
167 | sum := SumOfDigits(s) + SumOfDigits(ASource, odd(Length(ASource)));
|
---|
168 | check := 10 - sum mod 10;
|
---|
169 | if check = 10 then check := 0;
|
---|
170 |
|
---|
171 | Result := Result + IntToStr(check);
|
---|
172 | end;
|
---|
173 |
|
---|
174 | { Calculates a Modulo 11 check digit using the system discussed on Wikipedia -
|
---|
175 | see http://en.wikipedia.org/wiki/Talk:MSI_Barcode
|
---|
176 | Uses the IBM weight system }
|
---|
177 | function CheckSum_Plessey_Mod11(ASource: String): String;
|
---|
178 | var
|
---|
179 | i, sum, weight, check: Integer;
|
---|
180 | begin
|
---|
181 | sum := 0;
|
---|
182 | weight := 2;
|
---|
183 | for i := Length(ASource) downto 1 do
|
---|
184 | begin
|
---|
185 | inc(sum, weight * StrToInt(ASource[i]));
|
---|
186 | inc(weight);
|
---|
187 | if weight > 7 then weight := 2;
|
---|
188 | end;
|
---|
189 | check := (11 - sum mod 11) mod 11;
|
---|
190 |
|
---|
191 | Result := IntToStr(check);
|
---|
192 | end;
|
---|
193 |
|
---|
194 | { Calculates a Modulo 11 and a Modulo 10 check digit.
|
---|
195 | Combines the Barcode Island and Wikipedia code
|
---|
196 | Verified against http://www.bokai.com/BarcodeJSP/applet/BarcodeSampleApplet.htm
|
---|
197 | Weighted using the IBM system }
|
---|
198 | function Checksum_Plessey_Mod11_Mod10(ASource: String): String;
|
---|
199 | var
|
---|
200 | ch1, ch2: string;
|
---|
201 | begin
|
---|
202 | // Calculate first digit (mod 11)
|
---|
203 | ch1 := Checksum_Plessey_Mod11(ASource);
|
---|
204 |
|
---|
205 | // Calculated second digit (mod 10);
|
---|
206 | ch2 := CheckSum_Plessey_Mod10(ASource + ch1);
|
---|
207 |
|
---|
208 | Result := ch1 + ch2;
|
---|
209 | end;
|
---|
210 |
|
---|
211 |
|
---|
212 | { ------------------------------------------------------------------------------
|
---|
213 | Main MSI/Plessey routine
|
---|
214 | -------------------------------------------------------------------------------}
|
---|
215 | function msi_plessey(ASymbol: PZintSymbol; const ASource: String): Integer;
|
---|
216 | var
|
---|
217 | maxlen: Integer;
|
---|
218 | checkSumFunc: TCheckSumFunc;
|
---|
219 | begin
|
---|
220 | case ASymbol^.Option_2 of
|
---|
221 | 1: begin // one mod 10 check digit
|
---|
222 | checkSumFunc := @CheckSum_Plessey_Mod10;
|
---|
223 | maxlen := 18;
|
---|
224 | end;
|
---|
225 | 2: begin // two mod 10 check digits
|
---|
226 | checksumfunc := @CheckSum_Plessey_Mod10_Mod10;
|
---|
227 | maxlen := 18;
|
---|
228 | end;
|
---|
229 | 3: begin // one mod 11 check digit
|
---|
230 | checksumfunc := @Checksum_Plessey_Mod11;
|
---|
231 | maxlen := 55;
|
---|
232 | end;
|
---|
233 | 4: begin // a mod 11 and a mod 10 check digit
|
---|
234 | checksumfunc := @Checksum_Plessey_Mod11_Mod10;
|
---|
235 | maxLen := 18;
|
---|
236 | end;
|
---|
237 | else
|
---|
238 | begin // no check digits
|
---|
239 | checkSumFunc := nil;
|
---|
240 | maxLen := 55;
|
---|
241 | end;
|
---|
242 | end;
|
---|
243 |
|
---|
244 | Result := basic_encoder(ASymbol, ASource,
|
---|
245 | maxlen, NEON, '21', MSITable, '121', checksumFunc, false);
|
---|
246 | end;
|
---|
247 |
|
---|
248 | end.
|
---|
249 |
|
---|