GS1 Syntax Dictionary: Linter reference
A reference to the AI component linter routines referred to by the GS1 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.
69{
70
71 /*
72 * Set of prime weights used to derive alpha check characters.
73 *
74 * Here we have the first 97 since that is the maximum length of any
75 * AI is currently 99. Implementations may choose to support longer
76 * data inputs.
77 *
78 */
79 static const unsigned int primes[] = {
80 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37,
81 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89,
82 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151,
83 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223,
84 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281,
85 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359,
86 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433,
87 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503,
88 509
89 };
90
91 /*
92 * Sequence of all characters in CSET 82, ordered by weight.
93 *
94 */
95 static const char* const cset82 =
96 "!\"%&'()*+,-./0123456789:;<=>?ABCDEFGHIJKLMNOPQRSTUVWXYZ_"
97 "abcdefghijklmnopqrstuvwxyz";
98
99 /*
100 * Sequence of all characters in CSET 32, ordered by weight.
101 *
102 */
103 static const char* const cset32 = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";
104
105 size_t i, pos, len;
106 unsigned int sum = 0;
107 const unsigned int *p;
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) {
118 if (err_pos) *err_pos = 0;
119 if (err_len) *err_len = len;
121 }
122
123 /*
124 * Constrain the length of the data to the number of primes that we
125 * have.
126 *
127 */
128 if (len > sizeof(primes) / sizeof(primes[0])) {
129 if (err_pos) *err_pos = 0;
130 if (err_len) *err_len = len;
132 }
133
134 /*
135 * Ensure that the data characters are in CSET 82
136 *
137 */
138 if ((pos = strspn(data, cset82)) < len - 2) {
139 if (err_pos) *err_pos = pos;
140 if (err_len) *err_len = 1;
142 }
143
144 /*
145 * Ensure that the check characters are in CSET 32
146 *
147 */
148 if ((pos = strspn(&data[len - 2], cset32)) != 2) {
149 if (err_pos) *err_pos = len - 2 + pos;
150 if (err_len) *err_len = 1;
152 }
153
154 /*
155 * Sum of data-character values weighted by increasing prime values,
156 * from right to left, modulo 1021.
157 *
158 * The check characters are valid when their values match the above
159 * data checksum with its 10-bit value split evenly into two 5-bit
160 * values.
161 *
162 * The data character values are defined by their respective positions
163 * in CSET 82.
164 *
165 * The check character pair values are defined by their respective
166 * positions in CSET 32.
167 *
168 */
169 p = primes + len - 3;
170 for (i = 0; i < len - 2; i++)
171 sum += (unsigned int)(strchr(cset82, data[i]) - cset82) * *p--;
172 sum %= 1021;
173
174 if (data[i] != cset32[sum >> 5] || data[i+1] != cset32[sum & 31]) {
175 if (err_pos) *err_pos = len - 2;
176 if (err_len) *err_len = 2;
178 }
179
180 return GS1_LINTER_OK;
181
182}
@ GS1_LINTER_TOO_LONG_FOR_CHECK_PAIR_IMPLEMENTATION
The component is too long to perform an alphanumeric check character pair calculation.
Definition gs1syntaxdictionary.h:75
@ GS1_LINTER_INCORRECT_CHECK_PAIR
The alphanumeric check-character pair are incorrect.
Definition gs1syntaxdictionary.h:73
@ GS1_LINTER_INVALID_CSET82_CHARACTER
A non-CSET 82 character was found where a CSET 82 character is expected.
Definition gs1syntaxdictionary.h:68
@ GS1_LINTER_TOO_SHORT_FOR_CHECK_PAIR
The component is too short to perform an alphanumeric check character pair calculation.
Definition gs1syntaxdictionary.h:74
@ GS1_LINTER_OK
No issues were detected by the linter.
Definition gs1syntaxdictionary.h:66
@ GS1_LINTER_INVALID_CSET32_CHARACTER
A non-CSET 32 character was found where a CSET 32 character is expected.
Definition gs1syntaxdictionary.h:70