summaryrefslogtreecommitdiff
path: root/backend/gs1.c
diff options
context:
space:
mode:
Diffstat (limited to 'backend/gs1.c')
-rw-r--r--backend/gs1.c322
1 files changed, 322 insertions, 0 deletions
diff --git a/backend/gs1.c b/backend/gs1.c
new file mode 100644
index 0000000..dbad2ca
--- /dev/null
+++ b/backend/gs1.c
@@ -0,0 +1,322 @@
+/* gs1.c - Verifies GS1 data */
+
+/*
+ libzint - the open source barcode library
+ Copyright (C) 2009 Robin Stuart <robin@zint.org.uk>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the project nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+*/
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#ifdef _MSC_VER
+#include <malloc.h>
+#endif
+#include "common.h"
+#include "gs1.h"
+
+/* This code does some checks on the integrity of GS1 data. It is not intended
+ to be bulletproof, nor does it report very accurately what problem was found
+ or where, but should prevent some of the more common encoding errors */
+
+void itostr(char ai_string[], int ai_value)
+{
+ int thou, hund, ten, unit;
+ char temp[2];
+
+ strcpy(ai_string, "(");
+ thou = ai_value / 1000;
+ hund = (ai_value - (1000 * thou)) / 100;
+ ten = (ai_value - ((1000 * thou) + (100 * hund))) / 10;
+ unit = ai_value - ((1000 * thou) + (100 * hund) + (10 * ten));
+
+ temp[1] = '\0';
+ if(ai_value >= 1000) { temp[0] = itoc(thou); concat(ai_string, temp); }
+ if(ai_value >= 100) { temp[0] = itoc(hund); concat(ai_string, temp); }
+ temp[0] = itoc(ten);
+ concat(ai_string, temp);
+ temp[0] = itoc(unit);
+ concat(ai_string, temp);
+ concat(ai_string, ")");
+}
+
+int gs1_verify(struct zint_symbol *symbol, unsigned char source[], const unsigned int src_len, char reduced[])
+{
+ int i, j, last_ai, ai_latch;
+ char ai_string[6];
+ int bracket_level, max_bracket_level, ai_length, max_ai_length, min_ai_length;
+ int ai_value[100], ai_location[100], ai_count, data_location[100], data_length[100];
+ int error_latch;
+
+ /* Detect extended ASCII characters */
+ for(i = 0; i < src_len; i++) {
+ if(source[i] >=128) {
+ strcpy(symbol->errtxt, "Extended ASCII characters are not supported by GS1");
+ return ERROR_INVALID_DATA;
+ }
+ if(source[i] < 32) {
+ strcpy(symbol->errtxt, "Control characters are not supported by GS1");
+ return ERROR_INVALID_DATA;
+ }
+ }
+
+ if(source[0] != '[') {
+ strcpy(symbol->errtxt, "Data does not start with an AI");
+ return ERROR_INVALID_DATA;
+ }
+
+ /* Check the position of the brackets */
+ bracket_level = 0;
+ max_bracket_level = 0;
+ ai_length = 0;
+ max_ai_length = 0;
+ min_ai_length = 5;
+ j = 0;
+ ai_latch = 0;
+ for(i = 0; i < src_len; i++) {
+ ai_length += j;
+ if(((j == 1) && (source[i] != ']')) && ((source[i] < '0') || (source[i] > '9'))) { ai_latch = 1; }
+ if(source[i] == '[') { bracket_level++; j = 1; }
+ if(source[i] == ']') {
+ bracket_level--;
+ if(ai_length < min_ai_length) { min_ai_length = ai_length; }
+ j = 0;
+ ai_length = 0;
+ }
+ if(bracket_level > max_bracket_level) { max_bracket_level = bracket_level; }
+ if(ai_length > max_ai_length) { max_ai_length = ai_length; }
+ }
+ min_ai_length--;
+
+ if(bracket_level != 0) {
+ /* Not all brackets are closed */
+ strcpy(symbol->errtxt, "Malformed AI in input data (brackets don\'t match)");
+ return ERROR_INVALID_DATA;
+ }
+
+ if(max_bracket_level > 1) {
+ /* Nested brackets */
+ strcpy(symbol->errtxt, "Found nested brackets in input data");
+ return ERROR_INVALID_DATA;
+ }
+
+ if(max_ai_length > 4) {
+ /* AI is too long */
+ strcpy(symbol->errtxt, "Invalid AI in input data (AI too long)");
+ return ERROR_INVALID_DATA;
+ }
+
+ if(min_ai_length <= 1) {
+ /* AI is too short */
+ strcpy(symbol->errtxt, "Invalid AI in input data (AI too short)");
+ return ERROR_INVALID_DATA;
+ }
+
+ if(ai_latch == 1) {
+ /* Non-numeric data in AI */
+ strcpy(symbol->errtxt, "Invalid AI in input data (non-numeric characters in AI)");
+ return ERROR_INVALID_DATA;
+ }
+
+ ai_count = 0;
+ for(i = 1; i < src_len; i++) {
+ if(source[i - 1] == '[') {
+ ai_location[ai_count] = i;
+ j = 0;
+ do {
+ ai_string[j] = source[i + j];
+ j++;
+ } while (ai_string[j - 1] != ']');
+ ai_string[j - 1] = '\0';
+ ai_value[ai_count] = atoi(ai_string);
+ ai_count++;
+ }
+ }
+
+ for(i = 0; i < ai_count; i++) {
+ data_location[i] = ai_location[i] + 3;
+ if(ai_value[i] >= 100) { data_location[i]++; }
+ if(ai_value[i] >= 1000) { data_location[i]++; }
+ data_length[i] = 0;
+ do {
+ data_length[i]++;
+ } while ((source[data_location[i] + data_length[i] - 1] != '[') && (source[data_location[i] + data_length[i] - 1] != '\0'));
+ data_length[i]--;
+ }
+
+ for(i = 0; i < ai_count; i++) {
+ if(data_length[i] == 0) {
+ /* No data for given AI */
+ strcpy(symbol->errtxt, "Empty data field in input data");
+ return ERROR_INVALID_DATA;
+ }
+ }
+
+ error_latch = 0;
+ strcpy(ai_string, "");
+ for(i = 0; i < ai_count; i++) {
+ switch (ai_value[i]) {
+ case 0: if(data_length[i] != 18) { error_latch = 1; } break;
+ case 1:
+ case 2:
+ case 3: if(data_length[i] != 14) { error_latch = 1; } break;
+ case 4: if(data_length[i] != 16) { error_latch = 1; } break;
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ case 16:
+ case 17:
+ case 18:
+ case 19: if(data_length[i] != 6) { error_latch = 1; } break;
+ case 20: if(data_length[i] != 2) { error_latch = 1; } break;
+ case 23:
+ case 24:
+ case 25:
+ case 39:
+ case 40:
+ case 41:
+ case 42:
+ case 70:
+ case 80:
+ case 81: error_latch = 2; break;
+ }
+ if(
+ ((ai_value[i] >= 100) && (ai_value[i] <= 179))
+ || ((ai_value[i] >= 1000) && (ai_value[i] <= 1799))
+ || ((ai_value[i] >= 200) && (ai_value[i] <= 229))
+ || ((ai_value[i] >= 2000) && (ai_value[i] <= 2299))
+ || ((ai_value[i] >= 300) && (ai_value[i] <= 309))
+ || ((ai_value[i] >= 3000) && (ai_value[i] <= 3099))
+ || ((ai_value[i] >= 31) && (ai_value[i] <= 36))
+ || ((ai_value[i] >= 310) && (ai_value[i] <= 369))
+ ) {
+ error_latch = 2;
+ }
+ if((ai_value[i] >= 3100) && (ai_value[i] <= 3699)) {
+ if(data_length[i] != 6) {
+ error_latch = 1;
+ }
+ }
+ if(
+ ((ai_value[i] >= 370) && (ai_value[i] <= 379))
+ || ((ai_value[i] >= 3700) && (ai_value[i] <= 3799))
+ ) {
+ error_latch = 2;
+ }
+ if((ai_value[i] >= 410) && (ai_value[i] <= 415)) {
+ if(data_length[i] != 13) {
+ error_latch = 1;
+ }
+ }
+ if(
+ ((ai_value[i] >= 4100) && (ai_value[i] <= 4199))
+ || ((ai_value[i] >= 700) && (ai_value[i] <= 703))
+ || ((ai_value[i] >= 800) && (ai_value[i] <= 810))
+ || ((ai_value[i] >= 900) && (ai_value[i] <= 999))
+ || ((ai_value[i] >= 9000) && (ai_value[i] <= 9999))
+ ) {
+ error_latch = 2;
+ }
+ if((error_latch < 4) && (error_latch > 0)) {
+ /* error has just been detected: capture AI */
+ itostr(ai_string, ai_value[i]);
+ error_latch += 4;
+ }
+ }
+
+ if(error_latch == 5) {
+ strcpy(symbol->errtxt, "Invalid data length for AI ");
+ concat(symbol->errtxt, ai_string);
+ return ERROR_INVALID_DATA;
+ }
+
+ if(error_latch == 6) {
+ strcpy(symbol->errtxt, "Invalid AI value ");
+ concat(symbol->errtxt, ai_string);
+ return ERROR_INVALID_DATA;
+ }
+
+ /* Resolve AI data - put resulting string in 'reduced' */
+ j = 0;
+ last_ai = 0;
+ ai_latch = 1;
+ for(i = 0; i < src_len; i++) {
+ if((source[i] != '[') && (source[i] != ']')) {
+ reduced[j++] = source[i];
+ }
+ if(source[i] == '[') {
+ /* Start of an AI string */
+ if(ai_latch == 0) {
+ reduced[j++] = '[';
+ }
+ ai_string[0] = source[i + 1];
+ ai_string[1] = source[i + 2];
+ ai_string[2] = '\0';
+ last_ai = atoi(ai_string);
+ ai_latch = 0;
+ /* The following values from "GS-1 General Specification version 8.0 issue 2, May 2008"
+ figure 5.4.8.2.1 - 1 "Element Strings with Pre-Defined Length Using Application Identifiers" */
+ if(
+ ((last_ai >= 0) && (last_ai <= 4))
+ || ((last_ai >= 11) && (last_ai <= 20))
+ || (last_ai == 23) /* legacy support - see 5.3.8.2.2 */
+ || ((last_ai >= 31) && (last_ai <= 36))
+ || (last_ai == 41)
+ ) {
+ ai_latch = 1;
+ }
+ }
+ /* The ']' character is simply dropped from the input */
+ }
+ reduced[j] = '\0';
+
+ /* the character '[' in the reduced string refers to the FNC1 character */
+ return 0;
+}
+
+int ugs1_verify(struct zint_symbol *symbol, unsigned char source[], const unsigned int src_len, unsigned char reduced[])
+{
+ /* Only to keep the compiler happy */
+#ifndef _MSC_VER
+ char temp[src_len + 5];
+#else
+ char* temp = (char*)_alloca(src_len + 5);
+#endif
+ int error_number;
+
+ error_number = gs1_verify(symbol, source, src_len, temp);
+ if(error_number != 0) { return error_number; }
+
+ if (strlen(temp) < src_len + 5) {
+ ustrcpy(reduced, (unsigned char*)temp);
+ return 0;
+ }
+ strcpy(symbol->errtxt, "ugs1_verify overflow");
+ return ERROR_INVALID_DATA;
+}