source: trunk/Packages/lazbarcodes/src/lbc_gs1.pas

Last change on this file was 123, checked in by chronos, 3 years ago
  • Added: QR code image visible in contact others tab. It can be saved as image to file.
File size: 8.8 KB
Line 
1unit lbc_gs1;
2
3{
4 Based on Zint (done by Robin Stuart and the Zint team)
5 http://github.com/zint/zint
6
7 and translation by TheUnknownOnes
8 http://theunknownones.net
9}
10
11{$IFDEF FPC}
12{$mode objfpc}{$H+}
13{$ENDIF}
14
15interface
16
17uses
18 SysUtils, Types,
19 zint;
20
21function gs1_verify(ASymbol: PZintSymbol; ASource: PByte; const src_len: Integer;
22 var reduced: TCharDynArray): Integer;
23function ugs1_verify(ASymbol: PZintSymbol; ASource: PByte; src_len: Integer;
24 var reduced: TByteDynArray): Integer;
25
26implementation
27
28uses
29 lbc_helper;
30
31{ This code does some checks on the integrity of GS1 data. It is not intended
32 to be bulletproof, nor does it report very accurately what problem was found
33 or where, but should prevent some of the more common encoding errors.
34
35 wp: simplified a lot...}
36procedure itostr(var ai_string: String; ai_value: Integer);
37begin
38 ai_string := FormatFloat('(00)', ai_value);
39end;
40
41function gs1_verify(ASymbol: PZintSymbol; ASource: PByte; const src_len: Integer;
42 var reduced: TCharDynArray): Integer;
43var
44 i, j, last_ai, ai_latch : Integer;
45 ai_string: String;
46 bracket_level, max_bracket_level, ai_length, max_ai_length, min_ai_length: Integer;
47 ai_value, ai_location, data_location, data_length: array[0..99] of Integer;
48 ai_count: Integer;
49 error_latch: Integer;
50 P: PByte;
51 ch: Char;
52begin
53 { Detect extended ASCII characters }
54 P := PByte(ASource);
55 for i := 0 to src_len - 1 do
56 begin
57 if P^ >= 128 then
58 begin
59 ASymbol^.SetErrorText('Extended ASCII characters are not supported by GS1');
60 Result := ERROR_INVALID_DATA;
61 exit;
62 end;
63 if P^ < 32 then
64 begin
65 ASymbol^.SetErrorText('Control characters are not supported by GS1');
66 Result := ERROR_INVALID_DATA;
67 exit;
68 end;
69 inc(P);
70 end;
71
72 if ASource^ <> Ord('[') then
73 begin
74 ASymbol^.SetErrorText('Data does not start with an Application identifier');
75 Result := ERROR_INVALID_DATA;
76 exit;
77 end;
78
79 { Check the position of the brackets }
80 bracket_level := 0;
81 max_bracket_level := 0;
82 ai_length := 0;
83 max_ai_length := 0;
84 min_ai_length := 5;
85 j := 0;
86 ai_latch := 0;
87 P := ASource;
88 for i := 0 to src_len - 1 do
89 begin
90 Inc(ai_length, j);
91 if ((j = 1) and (P^ <> Ord(']'))) and
92 ((P^ < Ord('0')) or (P^ > Ord('9')))
93 then
94 ai_latch := 1;
95 if (P^ = Ord('[')) then begin
96 Inc(bracket_level);
97 j := 1;
98 end;
99 if (P^ = Ord(']')) then
100 begin
101 Dec(bracket_level);
102 if (ai_length < min_ai_length) then min_ai_length := ai_length;
103 j := 0;
104 ai_length := 0;
105 end;
106 if (bracket_level > max_bracket_level) then
107 max_bracket_level := bracket_level;
108 if (ai_length > max_ai_length) then
109 max_ai_length := ai_length;
110 inc(P);
111 end;
112 Dec(min_ai_length);
113
114 if (bracket_level <> 0) then
115 begin
116 { Not all brackets are closed }
117 ASymbol^.SetErrorText('Malformed Application Identifier in input data (brackets don''t match)');
118 Result := ERROR_INVALID_DATA;
119 exit;
120 end;
121
122 if (max_bracket_level > 1) then
123 begin
124 { Nested brackets }
125 ASymbol^.SetErrorText('Found nested brackets in input data');
126 Result := ERROR_INVALID_DATA;
127 exit;
128 end;
129
130 if (max_ai_length > 4) then
131 begin
132 { AI is too long }
133 ASymbol^.SetErrorText('Invalid Application Identifier (AI) in input data (AI too long - max 4 characters)');
134 Result := ERROR_INVALID_DATA;
135 exit;
136 end;
137
138 if (min_ai_length <= 1) then
139 begin
140 { AI is too short }
141 ASymbol^.SetErrorText('Invalid Application Identifier (AI) in input data (AI too short, at least 2 characters)');
142 result := ERROR_INVALID_DATA;
143 exit;
144 end;
145
146 if (ai_latch = 1) then
147 begin
148 { Non-numeric data in AI }
149 ASymbol^.SetErrorText('Invalid Application Identifier (AI) in input data (non-numeric characters in AI)');
150 result := ERROR_INVALID_DATA;
151 exit;
152 end;
153
154 ai_count := 0;
155 i := 1;
156 while i < src_len do
157 begin
158 if char(ASource[i-1]) = '[' then
159 begin
160 ai_location[ai_count] := i;
161 ch := char(ASource[i]);
162 ai_string := '';
163 while ch <> ']' do
164 begin
165 ai_string := ai_string + ch;
166 inc(i);
167 ch := char(ASource[i]);
168 end;
169 ai_value[ai_count] := StrToInt(ai_string);
170 inc(ai_count);
171 end else
172 inc(i);
173 end;
174
175 for i := 0 to ai_count - 1 do
176 begin
177 data_location[i] := ai_location[i] + 3;
178 if (ai_value[i] >= 100) then Inc(data_location[i]);
179 if (ai_value[i] >= 1000) then Inc(data_location[i]);
180 data_length[i] := 0;
181 repeat
182 inc(data_length[i]);
183 until not ((ASource[data_location[i] + data_length[i] - 1] <> Ord('[')) and
184 (ASource[data_location[i] + data_length[i] - 1] <> 0));
185 dec(data_length[i]);
186 end;
187
188 for i := 0 to ai_count - 1 do
189 begin
190 if (data_length[i] = 0) then
191 begin
192 { No data for given AI }
193 strcpy(ASymbol^.errtxt, 'Empty data field in input data');
194 Result := ERROR_INVALID_DATA;
195 exit;
196 end;
197 end;
198
199 error_latch := 0;
200 ai_string := '';
201 for i := 0 to ai_count - 1 do
202 begin
203 case ai_value[i] of
204 0:
205 if (data_length[i] <> 18) then error_latch := 1;
206 1, 2, 3:
207 if (data_length[i] <> 14) then error_latch := 1;
208 4:
209 if (data_length[i] <> 16) then error_latch := 1;
210 11, 12, 13, 14, 15, 16, 17, 18, 19:
211 if(data_length[i] <> 6) then error_latch := 1;
212 20:
213 if(data_length[i] <> 2) then error_latch := 1;
214 23, 24, 25, 39, 40, 41, 42, 70, 80, 81:
215 error_latch := 2;
216 end;
217
218 if ( ((ai_value[i] >= 100) and (ai_value[i] <= 179) ) or
219 ((ai_value[i] >= 1000) and (ai_value[i] <= 1799)) or
220 ((ai_value[i] >= 200) and (ai_value[i] <= 229)) or
221 ((ai_value[i] >= 2000) and (ai_value[i] <= 2299)) or
222 ((ai_value[i] >= 300) and (ai_value[i] <= 309)) or
223 ((ai_value[i] >= 3000) and (ai_value[i] <= 3099)) or
224 ((ai_value[i] >= 31) and (ai_value[i] <= 36)) or
225 ((ai_value[i] >= 310) and (ai_value[i] <= 369))
226 )
227 then
228 error_latch := 2;
229
230 if (ai_value[i] >= 3100) and (ai_value[i] <= 3699) then
231 begin
232 if (data_length[i] <> 6) then
233 error_latch := 1;
234 end;
235
236 if ( ((ai_value[i] >= 370) and (ai_value[i] <= 379)) or
237 ((ai_value[i] >= 3700) and (ai_value[i] <= 3799)) )
238 then
239 error_latch := 2;
240
241 if (ai_value[i] >= 410) and (ai_value[i] <= 415) then
242 begin
243 if (data_length[i] <> 13) then
244 error_latch := 1;
245 end;
246
247 if ( ((ai_value[i] >= 4100) and (ai_value[i] <= 4199)) or
248 ((ai_value[i] >= 700) and (ai_value[i] <= 703)) or
249 ((ai_value[i] >= 800) and (ai_value[i] <= 810)) or
250 ((ai_value[i] >= 900) and (ai_value[i] <= 999)) or
251 ((ai_value[i] >= 9000) and (ai_value[i] <= 9999)) )
252 then
253 error_latch := 2;
254
255 if ((error_latch < 4) and (error_latch > 0)) then
256 begin
257 { error has just been detected: capture AI }
258 itostr(ai_string, ai_value[i]);
259 Inc(error_latch, 4);
260 end;
261 end;
262
263 if (error_latch = 5) then
264 begin
265 ASymbol^.SetErrorText('Invalid data length for Application Identifier ' + ai_string);
266 Result := ERROR_INVALID_DATA;
267 exit;
268 end;
269
270 if (error_latch = 6) then
271 begin
272 ASymbol^.SetErrorText('Invalid Application Identifier value ' + ai_string);
273 result := ERROR_INVALID_DATA;
274 exit;
275 end;
276
277 { Resolve AI data - put resulting string in 'reduced' }
278 j := 0;
279
280 //last_ai := 0;
281 ai_latch := 1;
282 for i := 0 to src_len - 1 do
283 begin
284 if ((ASource[i] <> Ord('[')) and (ASource[i] <> Ord(']'))) then
285 begin
286 reduced[j] := Char(ASource[i]);
287 Inc(j);
288 end;
289 if (ASource[i] = Ord('[')) then
290 begin
291 { Start of an AI string }
292 if(ai_latch = 0) then
293 begin
294 reduced[j] := '[';
295 Inc(j);
296 end;
297 ai_string := Char(ASource[i+1]) + Char(ASource[i+2]);
298 last_ai := StrToInt(ai_string);
299 ai_latch := 0;
300
301 { The following values from "GS-1 General Specification version 8.0 issue 2, May 2008"
302 figure 5.4.8.2.1 - 1 "Element Strings with Pre-Defined Length Using Application Identifiers" }
303 if (last_ai in [0..4, 11..20, 23, 31..36, 41]) then
304 ai_latch := 1;
305 end;
306
307 { The ']' character is simply dropped from the input }
308 end;
309 reduced[j] := #0;
310
311 { the character '[' in the reduced string refers to the FNC1 character }
312 Result := 0;
313end;
314
315function ugs1_verify(ASymbol: PZintSymbol; ASource: PByte; src_len: Integer;
316 var reduced: TByteDynArray): Integer;
317var
318 temp: TCharDynArray = nil;
319begin
320 SetLength(temp, src_len + 5);
321 Result := gs1_verify(ASymbol, ASource, src_len, temp);
322 if (Result <> 0) then
323 exit;
324
325 if (strlen(temp) < src_len + 5) then begin
326 strcpy(PChar(@reduced[0]), PChar(@temp[0]));
327 Result := 0;
328 exit;
329 end;
330
331 ASymbol^.SetErrorText('ugs1_verify overflow');
332 result := ERROR_INVALID_DATA;
333end;
334
335end.
Note: See TracBrowser for help on using the repository browser.