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 pos, len;
107 unsigned int sum = 0;
108
109 assert(data);
110
111 len = strlen(data);
112
113 /*
114 * Data must include at least the check character pair.
115 *
116 */
117 if (len < 2)
120 0,
121 len
122 );
123
124 /*
125 * Constrain the length of the data to the number of primes that we
126 * have.
127 *
128 */
129 if (len - 2 > sizeof(primes) / sizeof(primes[0]))
132 0,
133 len
134 );
135
136 /*
137 * Ensure that the data characters are in CSET 82
138 *
139 */
140 if ((pos = strspn(data, cset82)) < len - 2)
143 pos,
144 1
145 );
146
147 /*
148 * Ensure that the check characters are in CSET 32
149 *
150 */
151 if ((pos = strspn(&data[len - 2], cset32)) != 2)
154 len - 2 + pos,
155 1
156 );
157
158 /*
159 * Sum of data-character values weighted by increasing prime values,
160 * from right to left, modulo 1021.
161 *
162 * The check characters are valid when their values match the above
163 * data checksum with its 10-bit value split evenly into two 5-bit
164 * values.
165 *
166 * The data character values are defined by their respective positions
167 * in CSET 82.
168 *
169 * The check character pair values are defined by their respective
170 * positions in CSET 32.
171 *
172 */
173 if (len > 2) {
174 size_t i;
175 const unsigned int *p;
176
177 for (i = 0, p = primes + (len - 3); i < len - 2; i++, p--)
178 sum += (unsigned int)(strchr(cset82, data[i]) - cset82) * *p;
179 sum %= 1021;
180 }
181
182 if (data[len-2] != cset32[sum >> 5] || data[len-1] != cset32[sum & 31])
185 len - 2,
186 2
187 );
188
190
191}
#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