| 1 | { lbc_code.pas - Handles Code 11, 39, 39+ and 93, as well as channel_code
|
|---|
| 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 |
|
|---|
| 11 | unit lbc_code;
|
|---|
| 12 |
|
|---|
| 13 | {$mode objfpc}{$H+}
|
|---|
| 14 |
|
|---|
| 15 | interface
|
|---|
| 16 |
|
|---|
| 17 | uses
|
|---|
| 18 | SysUtils, zint;
|
|---|
| 19 |
|
|---|
| 20 | function code_11(ASymbol: PZintSymbol; const ASource: String): Integer;
|
|---|
| 21 | function c39(ASymbol: PZintSymbol; const ASource: String): Integer;
|
|---|
| 22 | function pharmazentral(ASymbol: PZintSymbol; const ASource: String): Integer;
|
|---|
| 23 | function ec39(ASymbol: PZIntSymbol; const ASource: String): Integer;
|
|---|
| 24 | function c93(ASymbol: PZintSymbol; const ASource: String): Integer;
|
|---|
| 25 | function channel_code(ASymbol: PZintSymbol; const ASource: String): Integer;
|
|---|
| 26 |
|
|---|
| 27 |
|
|---|
| 28 | implementation
|
|---|
| 29 |
|
|---|
| 30 | uses
|
|---|
| 31 | lbc_helper;
|
|---|
| 32 |
|
|---|
| 33 | const
|
|---|
| 34 | C11Table: array[0..10] of String = (
|
|---|
| 35 | '111121', '211121', '121121', '221111', '112121',
|
|---|
| 36 | '212111', '122111', '111221', '211211', '211111',
|
|---|
| 37 | '112111'
|
|---|
| 38 | );
|
|---|
| 39 |
|
|---|
| 40 | { Code 39 tables checked against ISO/IEC 16388:2007 }
|
|---|
| 41 | C39Table: array[0..42] of String = (
|
|---|
| 42 | // bar-space-bar-space-bar-space-..., given in width units
|
|---|
| 43 | '1112212111', '2112111121', '1122111121', '2122111111', '1112211121', // '0', '1', ...
|
|---|
| 44 | '2112211111', '1122211111', '1112112121', '2112112111', '1122112111',
|
|---|
| 45 | '2111121121', '1121121121', '2121121111', '1111221121', '2111221111', // 'A', 'B', ...
|
|---|
| 46 | '1121221111', '1111122121', '2111122111', '1121122111', '1111222111',
|
|---|
| 47 | '2111111221', '1121111221', '2121111211', '1111211221', '2111211211',
|
|---|
| 48 | '1121211211', '1111112221', '2111112211', '1121112211', '1111212211',
|
|---|
| 49 | '2211111121', '1221111121', '2221111111', '1211211121', '2211211111',
|
|---|
| 50 | '1221211111', '1211112121', '2211112111', '1221112111', '1212121111', // 'Z', '-', ..
|
|---|
| 51 | '1212111211', '1211121211', '1112121211'
|
|---|
| 52 | ); // Code 39 character assignments (Table 1)
|
|---|
| 53 |
|
|---|
| 54 | { Encoding the full ASCII character set in Code 39 (Table A2) }
|
|---|
| 55 | const EC39Ctrl: array[0..127] of String = (
|
|---|
| 56 | '%U', '$A', '$B', '$C', '$D', '$E', '$F', '$G', '$H', '$I',
|
|---|
| 57 | '$J', '$K', '$L', '$M', '$N', '$O', '$P', '$Q', '$R', '$S',
|
|---|
| 58 | '$T', '$U', '$V', '$W', '$X', '$Y', '$Z', '%A', '%B', '%C',
|
|---|
| 59 | '%D', '%E', ' ', '/A', '/B', '/C', '/D', '/E', '/F', '/G',
|
|---|
| 60 | '/H', '/I', '/J', '/K', '/L', '-', '.', '/O', '0', '1',
|
|---|
| 61 | '2', '3', '4', '5', '6', '7', '8', '9', '/Z', '%F',
|
|---|
| 62 | '%G', '%H', '%I', '%J', '%V', 'A', 'B', 'C', 'D', 'E',
|
|---|
| 63 | 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
|
|---|
| 64 | 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y',
|
|---|
| 65 | 'Z', '%K', '%L', '%M', '%N', '%O', '%W', '+A', '+B', '+C',
|
|---|
| 66 | '+D', '+E', '+F', '+G', '+H', '+I', '+J', '+K', '+L', '+M',
|
|---|
| 67 | '+N', '+O', '+P', '+Q', '+R', '+S', '+T', '+U', '+V', '+W',
|
|---|
| 68 | '+X', '+Y', '+Z', '%P', '%Q', '%R', '%S', '%T'
|
|---|
| 69 | );
|
|---|
| 70 |
|
|---|
| 71 | const C93Ctrl: array[0..127] of String = (
|
|---|
| 72 | 'bU', 'aA', 'aB', 'aC', 'aD', 'aE', 'aF', 'aG', 'aH', 'aI',
|
|---|
| 73 | 'aJ', 'aK', 'aL', 'aM', 'aN', 'aO', 'aP', 'aQ', 'aR', 'aS',
|
|---|
| 74 | 'aT', 'aU', 'aV', 'aW', 'aX', 'aY', 'aZ', 'bA', 'bB', 'bC',
|
|---|
| 75 | 'bD', 'bE', ' ', 'cA', 'cB', 'cC', 'cD', 'cE', 'cF', 'cG',
|
|---|
| 76 | 'cH', 'cI', 'cJ', 'cK', 'cL', 'cM', 'cN', 'cO', '0', '1',
|
|---|
| 77 | '2', '3', '4', '5', '6', '7', '8', '9', 'cZ', 'bF',
|
|---|
| 78 | 'bG', 'bH', 'bI', 'bJ', 'bV', 'A', 'B', 'C', 'D', 'E',
|
|---|
| 79 | 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
|
|---|
| 80 | 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y',
|
|---|
| 81 | 'Z', 'bK', 'bL', 'bM', 'bN', 'bO', 'bW', 'dA', 'dB', 'dC',
|
|---|
| 82 | 'dD', 'dE', 'dF', 'dG', 'dH', 'dI', 'dJ', 'dK', 'dL', 'dM',
|
|---|
| 83 | 'dN', 'dO', 'dP', 'dQ', 'dR', 'dS', 'dT', 'dU', 'dV', 'dW',
|
|---|
| 84 | 'dX', 'dY', 'dZ', 'bP', 'bQ', 'bR', 'bS', 'bT'
|
|---|
| 85 | );
|
|---|
| 86 |
|
|---|
| 87 | const C93Table: array[0..46] of String = (
|
|---|
| 88 | '131112', '111213', '111312', '111411', '121113', '121212', // '0'..'5'
|
|---|
| 89 | '121311', '111114', '131211', '141111', '211113', '211212', // '6'..'B'
|
|---|
| 90 | '211311', '221112', '221211', '231111', '112113', '112212', // 'C'..'H'
|
|---|
| 91 | '112311', '122112', '132111', '111123', '111222', '111321', // 'I'..'N'
|
|---|
| 92 | '121122', '131121', '212112', '212211', '211122', '211221', // 'O'..'T'
|
|---|
| 93 | '221121', '222111', '112122', '112221', '122121', '123111', // 'U'..'Z'
|
|---|
| 94 | '121131', '311112', '311211', '321111', '112131', '113121', // '-', '.', ' ', '$', '/', '+'
|
|---|
| 95 | '211131', '121221', '312111', '311121', '122211' // '%', 'a', 'b', 'c', 'c'
|
|---|
| 96 | );
|
|---|
| 97 |
|
|---|
| 98 |
|
|---|
| 99 | {-------------------------------------------------------------------------------
|
|---|
| 100 | Code 11
|
|---|
| 101 |
|
|---|
| 102 | Allowed characters:
|
|---|
| 103 | numeric digits (0-9), the hyphen character (-)
|
|---|
| 104 | (Code 11 derives its name from these 11 characters).
|
|---|
| 105 | Length:
|
|---|
| 106 | basically unlimited (function errors after 121 characters, though).
|
|---|
| 107 | -------------------------------------------------------------------------------}
|
|---|
| 108 | function CheckSum_C11(ASource: String): String;
|
|---|
| 109 | var
|
|---|
| 110 | i, len: Integer;
|
|---|
| 111 | c_digit, c_weight, c_count: Integer;
|
|---|
| 112 | k_digit, k_weight, k_count: Integer;
|
|---|
| 113 | weight: array of Integer = nil;
|
|---|
| 114 | begin
|
|---|
| 115 | len := Length(ASource);
|
|---|
| 116 | SetLength(weight, len + 1);
|
|---|
| 117 |
|
|---|
| 118 | // Determine weights
|
|---|
| 119 | for i := 0 to len-1 do
|
|---|
| 120 | begin
|
|---|
| 121 | if ASource[i+1] = '-' then
|
|---|
| 122 | weight[i] := 10
|
|---|
| 123 | else
|
|---|
| 124 | weight[i] := ctoi(ASource[i+1]);
|
|---|
| 125 | end;
|
|---|
| 126 |
|
|---|
| 127 | // Calculate C checksum
|
|---|
| 128 | c_weight := 1;
|
|---|
| 129 | c_count := 0;
|
|---|
| 130 | for i := len-1 downto 0 do
|
|---|
| 131 | begin
|
|---|
| 132 | inc(c_count, c_weight * weight[i]);
|
|---|
| 133 | inc(c_weight);
|
|---|
| 134 | if (c_weight > 10) then
|
|---|
| 135 | c_weight := 1;
|
|---|
| 136 | end;
|
|---|
| 137 | c_digit := c_count mod 11;
|
|---|
| 138 | weight[len] := c_digit;
|
|---|
| 139 | // weight is 0-based and has been allocated for len+1 elements.
|
|---|
| 140 |
|
|---|
| 141 | // Calculate K checksum
|
|---|
| 142 | k_weight := 1;
|
|---|
| 143 | k_count := 0;
|
|---|
| 144 | for i := len downto 0 do
|
|---|
| 145 | begin
|
|---|
| 146 | inc(k_count, k_weight * weight[i]);
|
|---|
| 147 | inc(k_weight);
|
|---|
| 148 | if (k_weight > 9) then
|
|---|
| 149 | k_weight := 1;
|
|---|
| 150 | end;
|
|---|
| 151 | k_digit := k_count mod 11;
|
|---|
| 152 |
|
|---|
| 153 | // Convert checksum to string
|
|---|
| 154 | Result := itoc(c_digit) + itoc(k_digit);
|
|---|
| 155 | if (Result[1] = 'A') then Result[1] := '-';
|
|---|
| 156 | if (Result[2] = 'A') then Result[2] := '-';
|
|---|
| 157 | end;
|
|---|
| 158 |
|
|---|
| 159 | function code_11(ASymbol: PZintSymbol; const ASource: String): Integer;
|
|---|
| 160 | begin
|
|---|
| 161 | Result := basic_encoder(ASymbol, ASource,
|
|---|
| 162 | 121, SODIUM, '112211', C11Table, '11221', @CheckSum_C11, false);
|
|---|
| 163 | end;
|
|---|
| 164 |
|
|---|
| 165 |
|
|---|
| 166 | {-------------------------------------------------------------------------------
|
|---|
| 167 | Code 39
|
|---|
| 168 | -------------------------------------------------------------------------------}
|
|---|
| 169 | function CheckSum_C39(ASource: String): String;
|
|---|
| 170 | var
|
|---|
| 171 | i, sum: Integer;
|
|---|
| 172 | begin
|
|---|
| 173 | sum := 0;
|
|---|
| 174 | for i := 1 to Length(ASource) do
|
|---|
| 175 | inc(sum, pos(ASource[i], SILVER) - 1);
|
|---|
| 176 |
|
|---|
| 177 | sum := sum mod 43;
|
|---|
| 178 |
|
|---|
| 179 | if (sum < 10) then
|
|---|
| 180 | Result := itoc(sum)
|
|---|
| 181 | else
|
|---|
| 182 | begin
|
|---|
| 183 | if (sum < 36) then
|
|---|
| 184 | Result := Char((sum - 10) + Ord('A'))
|
|---|
| 185 | else
|
|---|
| 186 | case sum of
|
|---|
| 187 | 36: Result := '-';
|
|---|
| 188 | 37: Result := '.';
|
|---|
| 189 | 38: Result := ' ';
|
|---|
| 190 | 39: Result := '$';
|
|---|
| 191 | 40: Result := '/';
|
|---|
| 192 | 41: Result := '+';
|
|---|
| 193 | 42: Result := #37;
|
|---|
| 194 | else
|
|---|
| 195 | Result := ' ';
|
|---|
| 196 | end;
|
|---|
| 197 | end;
|
|---|
| 198 |
|
|---|
| 199 | { Display a space check digit as _, otherwise it looks like an error }
|
|---|
| 200 | if (Result = ' ') then
|
|---|
| 201 | Result := '_';
|
|---|
| 202 | end;
|
|---|
| 203 |
|
|---|
| 204 | { LOGMARS uses wider 'wide' bars than normal Code 39 }
|
|---|
| 205 | procedure WiderBars(var s: String);
|
|---|
| 206 | var
|
|---|
| 207 | i: Integer;
|
|---|
| 208 | begin
|
|---|
| 209 | for i := 1 to Length(s) do
|
|---|
| 210 | if s[i]='2' then s[i] := '3';
|
|---|
| 211 | end;
|
|---|
| 212 |
|
|---|
| 213 | function c39(ASymbol: PZintSymbol; const ASource: String): Integer;
|
|---|
| 214 | var
|
|---|
| 215 | i, maxlen: Integer;
|
|---|
| 216 | startcode, stopcode: String;
|
|---|
| 217 | charcodes: array[0..42] of String;
|
|---|
| 218 | checkSumFunc: TCheckSumFunc;
|
|---|
| 219 | begin
|
|---|
| 220 | startcode := '1211212111';
|
|---|
| 221 | stopcode := '121121211';
|
|---|
| 222 | charcodes := C39Table;
|
|---|
| 223 | checkSumFunc := nil;
|
|---|
| 224 | maxlen := 74;
|
|---|
| 225 |
|
|---|
| 226 | if (ASymbol^.symbology = BARCODE_LOGMARS) or (ASymbol^.symbology = BARCODE_HIBC_39) then
|
|---|
| 227 | begin
|
|---|
| 228 | WiderBars(startcode);
|
|---|
| 229 | WiderBars(stopcode);
|
|---|
| 230 | for i := Low(charcodes) to High(charcodes) do
|
|---|
| 231 | WiderBars(charcodes[i]);
|
|---|
| 232 | end;
|
|---|
| 233 |
|
|---|
| 234 | if (ASymbol^.symbology = BARCODE_LOGMARS) or
|
|---|
| 235 | (ASymbol^.option_2 = 1) or
|
|---|
| 236 | (ASymbol^.option and OPTION_ADD_CHECKSUM = OPTION_ADD_CHECKSUM) then
|
|---|
| 237 | begin
|
|---|
| 238 | checkSumFunc := @CheckSum_C39;
|
|---|
| 239 | ASymbol^.Option := ASymbol^.Option or OPTION_ADD_CHECKSUM;
|
|---|
| 240 | end;
|
|---|
| 241 |
|
|---|
| 242 | if (ASymbol^.symbology = BARCODE_LOGMARS) then
|
|---|
| 243 | maxlen := 59;
|
|---|
| 244 |
|
|---|
| 245 | Result := basic_encoder(ASymbol, Uppercase(ASource),
|
|---|
| 246 | maxlen, SILVER, startcode, charcodes, stopcode, checkSumFunc, false);
|
|---|
| 247 |
|
|---|
| 248 | if ASymbol^.symbology = BARCODE_CODE39 then
|
|---|
| 249 | ASymbol^.SetText('*' + ASymbol^.GetText + '*');
|
|---|
| 250 | end;
|
|---|
| 251 |
|
|---|
| 252 |
|
|---|
| 253 | {-------------------------------------------------------------------------------
|
|---|
| 254 | Pharmazentral Nummer (PZN)
|
|---|
| 255 | -------------------------------------------------------------------------------}
|
|---|
| 256 | function pharmazentral(ASymbol: PZintSymbol; const ASource: String): Integer;
|
|---|
| 257 | var
|
|---|
| 258 | i, i0, error_number, zeros, digits, maxDigits, sum, src_len: Integer;
|
|---|
| 259 | localstr: String = '';
|
|---|
| 260 | check_digit: byte;
|
|---|
| 261 | begin
|
|---|
| 262 | digits := ASymbol^.option_3;
|
|---|
| 263 | if not (digits in [7, 8]) then
|
|---|
| 264 | raise Exception.Create('[pharmazentral] Number of digits can only be 7 or 8');
|
|---|
| 265 |
|
|---|
| 266 | maxDigits := digits - 1; // check-digit included
|
|---|
| 267 |
|
|---|
| 268 | src_len := Length(ASource);
|
|---|
| 269 | if (src_len > maxDigits) then
|
|---|
| 270 | begin
|
|---|
| 271 | ASymbol^.SetErrorText('Wrong input length');
|
|---|
| 272 | Result := ERROR_TOO_LONG;
|
|---|
| 273 | exit;
|
|---|
| 274 | end;
|
|---|
| 275 |
|
|---|
| 276 | error_number := is_sane(NEON, ASource);
|
|---|
| 277 | if (error_number = ERROR_INVALID_DATA) then
|
|---|
| 278 | begin
|
|---|
| 279 | ASymbol^.SetErrorText('Invalid characters in data');
|
|---|
| 280 | Result := error_number;
|
|---|
| 281 | exit;
|
|---|
| 282 | end;
|
|---|
| 283 |
|
|---|
| 284 | zeros := maxDigits - src_len;
|
|---|
| 285 | localstr := '-' + StringOfChar('0', zeros) + ASource;
|
|---|
| 286 |
|
|---|
| 287 | i0 := 7 - MaxDigits;
|
|---|
| 288 | sum := 0;
|
|---|
| 289 | for i := 1 to maxDigits do
|
|---|
| 290 | inc(sum, (i + i0) * ctoi(localstr[i+1]));
|
|---|
| 291 | // wp: i+1 is correct because '-' was added to localStr
|
|---|
| 292 |
|
|---|
| 293 | check_digit := sum mod 11;
|
|---|
| 294 | localstr := localstr + itoc(check_digit);
|
|---|
| 295 | if check_digit = ord('A') then
|
|---|
| 296 | begin
|
|---|
| 297 | ASymbol^.SetErrorText('Invalid PZN Data');
|
|---|
| 298 | Result := ERROR_INVALID_DATA;
|
|---|
| 299 | exit;
|
|---|
| 300 | end;
|
|---|
| 301 |
|
|---|
| 302 | Result := c39(ASymbol, localstr);
|
|---|
| 303 |
|
|---|
| 304 | ASymbol^.SetText('PZN' + localstr);
|
|---|
| 305 | end;
|
|---|
| 306 |
|
|---|
| 307 |
|
|---|
| 308 | {-------------------------------------------------------------------------------
|
|---|
| 309 | Extended Code 39 - ISO/IEC 16388:2007 Annex A
|
|---|
| 310 | -------------------------------------------------------------------------------}
|
|---|
| 311 |
|
|---|
| 312 | function ec39(ASymbol: PZintSymbol; const ASource: String): Integer;
|
|---|
| 313 | var
|
|---|
| 314 | i: Integer;
|
|---|
| 315 | buffer: string;
|
|---|
| 316 | check: char;
|
|---|
| 317 | begin
|
|---|
| 318 | if (Length(ASource) > 74) then
|
|---|
| 319 | begin
|
|---|
| 320 | ASymbol^.SetErrorText('Input too long (max 74 characters).');
|
|---|
| 321 | Result := ERROR_TOO_LONG;
|
|---|
| 322 | exit;
|
|---|
| 323 | end;
|
|---|
| 324 |
|
|---|
| 325 | { Creates a buffer string and places control characters into it }
|
|---|
| 326 | buffer := '';
|
|---|
| 327 | for i := 1 to Length(ASource) do
|
|---|
| 328 | begin
|
|---|
| 329 | if ASource[i] > #127 then
|
|---|
| 330 | begin
|
|---|
| 331 | { Cannot encode extended ASCII }
|
|---|
| 332 | ASymbol^.SetErrorText('Invalid character in input data');
|
|---|
| 333 | Result := ERROR_INVALID_DATA;
|
|---|
| 334 | exit;
|
|---|
| 335 | end;
|
|---|
| 336 | buffer := buffer + EC39Ctrl[byte(ASource[i])];
|
|---|
| 337 | end;
|
|---|
| 338 |
|
|---|
| 339 | { Then send the buffer to the C39 function }
|
|---|
| 340 | Result := c39(ASymbol, buffer);
|
|---|
| 341 |
|
|---|
| 342 | if ASymbol^.Option and OPTION_DISPLAY_CHECKSUM = OPTION_DISPLAY_CHECKSUM then
|
|---|
| 343 | begin
|
|---|
| 344 | // Retrieve appended check character
|
|---|
| 345 | buffer := ASymbol^.GetText;
|
|---|
| 346 | check := buffer[Length(buffer)];
|
|---|
| 347 | ASymbol^.SetText(aSource + check);
|
|---|
| 348 | end else
|
|---|
| 349 | ASymbol^.SetText(ASource);
|
|---|
| 350 | end;
|
|---|
| 351 |
|
|---|
| 352 |
|
|---|
| 353 | {-------------------------------------------------------------------------------
|
|---|
| 354 | Code 93
|
|---|
| 355 |
|
|---|
| 356 | An advancement on Code 39 and the definition is a lot tighter
|
|---|
| 357 |
|
|---|
| 358 | SILVER includes the extra characters a, b, c and d to represent Code 93 specific
|
|---|
| 359 | shift characters 1, 2, 3 and 4 respectively. These characters are never used by
|
|---|
| 360 | c39() and ec39()
|
|---|
| 361 | -------------------------------------------------------------------------------}
|
|---|
| 362 | function CheckSum_C93(ASource: String): String;
|
|---|
| 363 | var
|
|---|
| 364 | values: Array of Integer = nil;
|
|---|
| 365 | i: Integer;
|
|---|
| 366 | c, k, weight, len: Integer;
|
|---|
| 367 | begin
|
|---|
| 368 | len := Length(ASource);
|
|---|
| 369 | SetLength(values, len + 1); // Allocate one more element for check digit C
|
|---|
| 370 | for i := 1 to len do
|
|---|
| 371 | values[i-1] := pos(ASource[i], SILVER) - 1;
|
|---|
| 372 |
|
|---|
| 373 | { Check digit C }
|
|---|
| 374 | c := 0;
|
|---|
| 375 | weight := 1;
|
|---|
| 376 | for i := len-1 downto 0 do
|
|---|
| 377 | begin
|
|---|
| 378 | Inc(c, values[i] * weight);
|
|---|
| 379 | Inc(weight);
|
|---|
| 380 | if (weight = 21) then
|
|---|
| 381 | weight := 1;
|
|---|
| 382 | end;
|
|---|
| 383 | c := c mod 47;
|
|---|
| 384 | values[len] := c; // Element at index len has been allocated above!
|
|---|
| 385 |
|
|---|
| 386 | { Check digit K }
|
|---|
| 387 | k := 0;
|
|---|
| 388 | weight := 1;
|
|---|
| 389 | for i := len downto 0 do // Use len (rather than len-1) because of extra allocation
|
|---|
| 390 | begin
|
|---|
| 391 | Inc(k, values[i] * weight);
|
|---|
| 392 | Inc(weight);
|
|---|
| 393 | if (weight = 16) then
|
|---|
| 394 | weight := 1;
|
|---|
| 395 | end;
|
|---|
| 396 | k := k mod 47;
|
|---|
| 397 |
|
|---|
| 398 | Result := SILVER[c+1] + SILVER[k+1];
|
|---|
| 399 | end;
|
|---|
| 400 |
|
|---|
| 401 | function c93(ASymbol: PZintSymbol; const ASource: String): Integer;
|
|---|
| 402 | var
|
|---|
| 403 | i: Integer;
|
|---|
| 404 | buffer: String;
|
|---|
| 405 | check: String;
|
|---|
| 406 | begin
|
|---|
| 407 | if Length(ASource) > 107 then
|
|---|
| 408 | begin
|
|---|
| 409 | ASymbol^.SetErrorText('Input too long (max 107 characters).');
|
|---|
| 410 | Result := ERROR_TOO_LONG;
|
|---|
| 411 | exit;
|
|---|
| 412 | end;
|
|---|
| 413 |
|
|---|
| 414 | // Prepare message content
|
|---|
| 415 | buffer := '';
|
|---|
| 416 | for i := 1 to Length(ASource) do
|
|---|
| 417 | begin
|
|---|
| 418 | if ASource[i] > #127 then
|
|---|
| 419 | begin
|
|---|
| 420 | // Cannot encode extended ASCII
|
|---|
| 421 | ASymbol^.SetErrorText('Invalid characters in input data.');
|
|---|
| 422 | Result := ERROR_INVALID_DATA;
|
|---|
| 423 | exit;
|
|---|
| 424 | end;
|
|---|
| 425 | buffer := buffer + C93Ctrl[byte(ASource[i])];
|
|---|
| 426 | end;
|
|---|
| 427 |
|
|---|
| 428 | Result := basic_encoder(ASymbol, buffer,
|
|---|
| 429 | 107, SILVER, '111141', C93Table, '1111411', @CheckSum_C93, false
|
|---|
| 430 | );
|
|---|
| 431 |
|
|---|
| 432 | // Show the original input string as human-readable text
|
|---|
| 433 | if (Result = 0) then
|
|---|
| 434 | begin
|
|---|
| 435 | // If input string contains #0 replace it by space
|
|---|
| 436 | buffer := ASource;
|
|---|
| 437 | for i := 1 to Length(buffer) do
|
|---|
| 438 | if buffer[i] = #0 then buffer[i] := ' ';
|
|---|
| 439 | if (ASymbol^.Option and OPTION_DISPLAY_CHECKSUM <> 0) then
|
|---|
| 440 | begin
|
|---|
| 441 | // Extract check chars from generated symbol code...
|
|---|
| 442 | check := Copy(ASymbol^.GetText, Length(ASymbol^.GetText)-1, 2);
|
|---|
| 443 | // ... and append to original input string
|
|---|
| 444 | ASymbol^.SetText(buffer + check);
|
|---|
| 445 | end else
|
|---|
| 446 | ASymbol^.SetText(buffer);
|
|---|
| 447 | end;
|
|---|
| 448 | end;
|
|---|
| 449 |
|
|---|
| 450 |
|
|---|
| 451 | {-------------------------------------------------------------------------------
|
|---|
| 452 | channel_code
|
|---|
| 453 |
|
|---|
| 454 | NextS() and NextB() are from ANSI/AIM BC12-1998 and are Copyright (c) AIM 1997
|
|---|
| 455 |
|
|---|
| 456 | They are used here on the understanding that they form part of the
|
|---|
| 457 | specification for Channel Code and therefore their use is permitted under the
|
|---|
| 458 | following terms set out in that document:
|
|---|
| 459 |
|
|---|
| 460 | "It is the intent and understanding of AIM [t]hat the symbology presented in
|
|---|
| 461 | this specification is entirely in the public domain and free of all use
|
|---|
| 462 | restrictions, licenses and fees. AIM USA, its member companies, or individual
|
|---|
| 463 | officers assume no liability for the use of this document."
|
|---|
| 464 | -------------------------------------------------------------------------------}
|
|---|
| 465 |
|
|---|
| 466 | procedure CheckCharacter(var APattern: String; const AValue, ATarget_Value: Integer;
|
|---|
| 467 | const S, B: array of Integer);
|
|---|
| 468 | var
|
|---|
| 469 | i: Integer;
|
|---|
| 470 | begin
|
|---|
| 471 | if (AValue = ATarget_value) then
|
|---|
| 472 | begin
|
|---|
| 473 | { Target reached - save the generated pattern }
|
|---|
| 474 | APattern := '11110';
|
|---|
| 475 | for i := 0 to 10 do
|
|---|
| 476 | APattern := APattern + itoc(S[i]) + itoc(B[i]);
|
|---|
| 477 | end;
|
|---|
| 478 | end;
|
|---|
| 479 |
|
|---|
| 480 | procedure NextS(Chan, i, MaxS, MaxB: Integer; var S, B: array of Integer;
|
|---|
| 481 | var AValue, ATarget_value: Integer; var APattern: String); forward;
|
|---|
| 482 |
|
|---|
| 483 | procedure NextB(chan, i, MaxB, MaxS: Integer; var S, B: array of Integer;
|
|---|
| 484 | var AValue, ATarget_value: Integer; var APattern: String);
|
|---|
| 485 | var
|
|---|
| 486 | _b: Integer;
|
|---|
| 487 | begin
|
|---|
| 488 | if (S[i] + B[i-1] + S[i-1] + B[i-2] > 4) then
|
|---|
| 489 | _b := 1
|
|---|
| 490 | else
|
|---|
| 491 | _b := 2;
|
|---|
| 492 |
|
|---|
| 493 | if (i < Chan + 2) then
|
|---|
| 494 | begin
|
|---|
| 495 | while _b <= MaxB do
|
|---|
| 496 | begin
|
|---|
| 497 | B[i] := _b;
|
|---|
| 498 | NextS(Chan, i + 1, MaxS, MaxB + 1 - _b, S, B, AValue, ATarget_value, APattern);
|
|---|
| 499 | Inc(_b);
|
|---|
| 500 | end;
|
|---|
| 501 | end else
|
|---|
| 502 | if (_b <= MaxB) then
|
|---|
| 503 | begin
|
|---|
| 504 | B[i] := MaxB;
|
|---|
| 505 | CheckCharacter(APattern, AValue, ATarget_value, S, B);
|
|---|
| 506 | Inc(AValue);
|
|---|
| 507 | end;
|
|---|
| 508 | end;
|
|---|
| 509 |
|
|---|
| 510 | procedure NextS(Chan, i, MaxS, MaxB: Integer; var S, B: Array of Integer;
|
|---|
| 511 | var AValue, ATarget_value: Integer; var APattern: String);
|
|---|
| 512 | var
|
|---|
| 513 | _s: Integer;
|
|---|
| 514 | begin
|
|---|
| 515 | if (i < Chan + 2) then
|
|---|
| 516 | _s := 1
|
|---|
| 517 | else
|
|---|
| 518 | _s := MaxS;
|
|---|
| 519 | while _s <= MaxS do
|
|---|
| 520 | begin
|
|---|
| 521 | S[i] := _s;
|
|---|
| 522 | NextB(Chan, i, MaxB, MaxS + 1 - _s, S, B, AValue, ATarget_value, APattern);
|
|---|
| 523 | Inc(_s);
|
|---|
| 524 | end;
|
|---|
| 525 | end;
|
|---|
| 526 |
|
|---|
| 527 | { Channel Code - According to ANSI/AIM BC12-1998 }
|
|---|
| 528 | function channel_code(ASymbol: PZintSymbol; const ASource: String): Integer;
|
|---|
| 529 | var
|
|---|
| 530 | S: array[0..10] of Integer = (0,0,0,0,0,0,0,0,0,0,0);
|
|---|
| 531 | B: array[0..10] of Integer = (0,0,0,0,0,0,0,0,0,0,0);
|
|---|
| 532 | pattern: String = '';
|
|---|
| 533 | value, target_value: Integer;
|
|---|
| 534 | channels, i: Integer;
|
|---|
| 535 | error_number, zeros, src_len: Integer;
|
|---|
| 536 | outOfRange: Boolean;
|
|---|
| 537 | begin
|
|---|
| 538 | src_len := Length(ASource);
|
|---|
| 539 |
|
|---|
| 540 | if (src_len > 7) then
|
|---|
| 541 | begin
|
|---|
| 542 | ASymbol^.SetErrorText('Input too long');
|
|---|
| 543 | Result := ERROR_TOO_LONG;
|
|---|
| 544 | exit;
|
|---|
| 545 | end;
|
|---|
| 546 |
|
|---|
| 547 | error_number := is_sane(NEON, ASource);
|
|---|
| 548 | if (error_number = ERROR_INVALID_DATA) then
|
|---|
| 549 | begin
|
|---|
| 550 | ASymbol^.SetErrorText('Invalid characters in data');
|
|---|
| 551 | Result := error_number;
|
|---|
| 552 | exit;
|
|---|
| 553 | end;
|
|---|
| 554 |
|
|---|
| 555 | if (ASymbol^.option_2 < 3) or (ASymbol^.option_2 > 8) then
|
|---|
| 556 | channels := 0
|
|---|
| 557 | else
|
|---|
| 558 | channels := ASymbol^.option_2;
|
|---|
| 559 | if (channels = 0) then
|
|---|
| 560 | channels := src_len + 1;
|
|---|
| 561 | if (channels = 2) then
|
|---|
| 562 | channels := 3;
|
|---|
| 563 |
|
|---|
| 564 | target_value := 0;
|
|---|
| 565 | for i := 1 to src_len do
|
|---|
| 566 | target_value := target_value * 10 + ctoi(ASource[i]);
|
|---|
| 567 |
|
|---|
| 568 | outOfRange := false;
|
|---|
| 569 | case channels of
|
|---|
| 570 | 3: if (target_value > 26) then outOfRange := true;
|
|---|
| 571 | 4: if (target_value > 292) then outOfRange := true;
|
|---|
| 572 | 5: if (target_value > 3493) then outOfRange := true;
|
|---|
| 573 | 6: if (target_value > 44072) then outOfRange := true;
|
|---|
| 574 | 7: if (target_value > 576688) then outOfRange := true;
|
|---|
| 575 | 8: if (target_value > 7742862) then outOfRange := true;
|
|---|
| 576 | else outOfRange := true;
|
|---|
| 577 | end;
|
|---|
| 578 | if outOfRange then
|
|---|
| 579 | begin
|
|---|
| 580 | ASymbol^.SetErrorText('Value out of range');
|
|---|
| 581 | Result := ERROR_INVALID_DATA;
|
|---|
| 582 | exit;
|
|---|
| 583 | end;
|
|---|
| 584 |
|
|---|
| 585 | B[0] := 1;
|
|---|
| 586 | S[1] := 1;
|
|---|
| 587 | B[1] := 1;
|
|---|
| 588 | S[2] := 1;
|
|---|
| 589 | B[2] := 1;
|
|---|
| 590 | value := 0;
|
|---|
| 591 | NextS(channels, 3, channels, channels, S, B, value, target_value, pattern);
|
|---|
| 592 |
|
|---|
| 593 | expand(ASymbol, pattern);
|
|---|
| 594 |
|
|---|
| 595 | zeros := channels - 1 - src_len;
|
|---|
| 596 | ASymbol^.SetText(StringOfChar('0', zeros) + ASource);
|
|---|
| 597 |
|
|---|
| 598 | Result := error_number;
|
|---|
| 599 | end;
|
|---|
| 600 |
|
|---|
| 601 |
|
|---|
| 602 | end.
|
|---|
| 603 |
|
|---|