GS1 Barcode Syntax Tests reference
A reference to the AI component "linter" routines referred to by the GS1 Barcode Syntax Dictionary. Copyright (c) 2022-2024 GS1 AISBL.
lint_csumalpha.c File Reference

Purpose

The csumalpha linter ensures that the data has a valid alphanumeric check character pair.

Remarks
The process for validating the GS1 alphanumeric check character pair is described in the GS1 General Specifications section "Check character calculation (for alphanumeric keys)".

Functional Description

◆ gs1_lint_csumalpha()

GS1_SYNTAX_DICTIONARY_API gs1_lint_err_t gs1_lint_csumalpha ( const char *const  data,
size_t *const  err_pos,
size_t *const  err_len 
)

Used to ensure that the AI component has a valid alphanumeric check character pair.

Parameters
[in]dataPointer to the null-terminated data to be linted. Must not be NULL.
[out]err_posTo facilitate error highlighting, the start position of the bad data is written to this pointer, if not NULL.
[out]err_lenThe length of the bad data is written to this pointer, if not NULL.
Returns
GS1_LINTER_OK if okay.
GS1_LINTER_INCORRECT_CHECK_PAIR if the data contains an incorrect check character pair.
GS1_LINTER_TOO_SHORT_FOR_CHECK_PAIR if the data is too short.
GS1_LINTER_TOO_LONG_FOR_CHECK_PAIR_IMPLEMENTATION if the data is too long for this implementation of the check character pair algorithm. GS1_LINTER_INVALID_CSET82_CHARACTER if any of the data characters are not in CSET 82. GS1_LINTER_INVALID_CSET32_CHARACTER if any of the data characters are not in CSET 32.
Note
The return value GS1_LINTER_TOO_LONG_FOR_CHECK_PAIR_IMPLEMENTATION represents exceeding an implementation-specific limit. Some implmenetations may choose to support longer data inputs.
70{
71
72 /*
73 * Set of prime weights used to derive alpha check characters.
74 *
75 * Here we have the first 97 since that is the maximum length of any
76 * AI is currently 99. Implementations may choose to support longer
77 * data inputs.
78 *
79 */
80 static const unsigned int primes[] = {
81 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37,
82 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89,
83 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151,
84 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223,
85 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281,
86 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359,
87 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433,
88 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503,
89 509
90 };
91
92 /*
93 * Sequence of all characters in CSET 82, ordered by weight.
94 *
95 */
96 static const char* const cset82 =
97 "!\"%&'()*+,-./0123456789:;<=>?ABCDEFGHIJKLMNOPQRSTUVWXYZ_"
98 "abcdefghijklmnopqrstuvwxyz";
99
100 /*
101 * Sequence of all characters in CSET 32, ordered by weight.
102 *
103 */
104 static const char* const cset32 = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";
105
106 size_t i, pos, len;
107 unsigned int sum = 0;
108 const unsigned int *p;
109
110 assert(data);
111
112 len = strlen(data);
113
114 /*
115 * Data must include at least the check character pair.
116 *
117 */
118 if (len < 2)
121 0,
122 len
123 );
124
125 /*
126 * Constrain the length of the data to the number of primes that we
127 * have.
128 *
129 */
130 if (len > sizeof(primes) / sizeof(primes[0]))
133 0,
134 len
135 );
136
137 /*
138 * Ensure that the data characters are in CSET 82
139 *
140 */
141 if ((pos = strspn(data, cset82)) < len - 2)
144 pos,
145 1
146 );
147
148 /*
149 * Ensure that the check characters are in CSET 32
150 *
151 */
152 if ((pos = strspn(&data[len - 2], cset32)) != 2)
155 len - 2 + pos,
156 1
157 );
158
159 /*
160 * Sum of data-character values weighted by increasing prime values,
161 * from right to left, modulo 1021.
162 *
163 * The check characters are valid when their values match the above
164 * data checksum with its 10-bit value split evenly into two 5-bit
165 * values.
166 *
167 * The data character values are defined by their respective positions
168 * in CSET 82.
169 *
170 * The check character pair values are defined by their respective
171 * positions in CSET 32.
172 *
173 */
174 p = primes + len - 3;
175 for (i = 0; i < len - 2; i++)
176 sum += (unsigned int)(strchr(cset82, data[i]) - cset82) * *p--;
177 sum %= 1021;
178
179 if (data[i] != cset32[sum >> 5] || data[i+1] != cset32[sum & 31])
182 len - 2,
183 2
184 );
185
187
188}
#define GS1_LINTER_RETURN_ERROR(error, position, length)
Return from a linter indicating that a problem was detected with the given data.
Definition gs1syntaxdictionary-utils.h:77
#define GS1_LINTER_RETURN_OK
Return from a linter indicating that no problem was detected with the given data.
Definition gs1syntaxdictionary-utils.h:62
@ GS1_LINTER_TOO_LONG_FOR_CHECK_PAIR_IMPLEMENTATION
The component is too long to perform an alphanumeric check character pair calculation.
Definition gs1syntaxdictionary.h:86
@ GS1_LINTER_INCORRECT_CHECK_PAIR
The alphanumeric check-character pair are incorrect.
Definition gs1syntaxdictionary.h:84
@ GS1_LINTER_INVALID_CSET82_CHARACTER
A non-CSET 82 character was found where a CSET 82 character is expected.
Definition gs1syntaxdictionary.h:79
@ GS1_LINTER_TOO_SHORT_FOR_CHECK_PAIR
The component is too short to perform an alphanumeric check character pair calculation.
Definition gs1syntaxdictionary.h:85
@ GS1_LINTER_INVALID_CSET32_CHARACTER
A non-CSET 32 character was found where a CSET 32 character is expected.
Definition gs1syntaxdictionary.h:81