GS1 Syntax Dictionary: Linter reference
A reference to the AI component linter routines referred to by the GS1 Syntax Dictionary.
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