summaryrefslogtreecommitdiff
path: root/src/upc.c
blob: a81979b4fd8a7a7cfbc5ac410d185c9c14b61ce0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define UPC_A_WIDTH 95
#define UPC_A_NUMDIGITS 12

const char UPC_A_GUARD_PATTERN_SE[3] = { 1, 0, 1 };
const char UPC_A_GUARD_PATTERN_M[5] = { 0, 1, 0, 1, 0 };

const char UPC_DIGIT[10][7] = { { 0, 0, 0, 1, 1, 0, 1 }, 
                                { 0, 0, 1, 1, 0, 0, 1 }, 
                                { 0, 0, 1, 0, 0, 1, 1 }, 
                                { 0, 1, 1, 1, 1, 0, 1 }, 
                                { 0, 1, 0, 0, 0, 1, 1 }, 
                                { 0, 1, 1, 0, 0, 0, 1 },
                                { 0, 1, 0, 1, 1, 1, 1 },
                                { 0, 1, 1, 1, 0, 1, 1 },
                                { 0, 1, 1, 0, 1, 1, 1 },
                                { 0, 0, 0, 1, 0, 1, 1 } };

static char upc_calculate_check_digit( char *digits );
static void upc_draw_pattern( char buffer[], int *index, const char *pattern, int pattern_size );
static void upc_draw_digits( char *buffer, int *index, char *digits, char isLeft );

const char* create_upc_a( char *input ) {

    // allocate 95 bytes of memory for resultant data
    char *result = malloc(UPC_A_WIDTH);
    // create a char array to store the GTIN-12 number
    char digits[UPC_A_NUMDIGITS];

    int index = 0;

    // copy digits from function param to local array
    memcpy( digits, input, UPC_A_NUMDIGITS );

    // set the final digit to the appropriate check digit
    // digits[11] = upc_calculate_check_digit( digits );

    // draw start guard pattern
    upc_draw_pattern( result, &index, UPC_A_GUARD_PATTERN_SE, sizeof(UPC_A_GUARD_PATTERN_SE) );

    // draw LLLLLL digits
    upc_draw_digits( result, &index, digits, 1 );

    // draw middle guard pattern
    upc_draw_pattern( result, &index, UPC_A_GUARD_PATTERN_M, sizeof(UPC_A_GUARD_PATTERN_M) );

    // draw RRRRRR digits
    upc_draw_digits( result, &index, digits, 0 );    

    // draw end guard pattern
    upc_draw_pattern( result, &index, UPC_A_GUARD_PATTERN_SE, sizeof(UPC_A_GUARD_PATTERN_SE) );

    return result;
}

char upc_a_calculate_check_digit( char *digits ) {

    char result = 0;
    int M;

    // 1. Sum digits at odd-numbered positions   
    for( int i = 0; i < UPC_A_NUMDIGITS; ++i ) {
        if( i % 2 == 0 ) { result += digits[i]; }
    }
    // 2. Multiply result by 3
    result *= 3;
    // 3. Add digits at even-numbered positions to the result
    for( int i = 0; i < UPC_A_NUMDIGITS; ++i ) {
        if( i % 2 != 0 ) { result += digits[i]; }
    }
    // 4. Find the result mod 10 and call it "M"
    M = result % 10;
    // 5. If M is zero, the check digit is 0,
    if( M == 0 ) { result = M; }
    // otherwise the check digit is 10 - M
    else {
        result = 10 - M;
    }

    return result;
}

static void upc_draw_pattern( char buffer[], int *index, const char *pattern, int pattern_size ) {

    for( int i = 0; i < pattern_size; ++i ) {
        buffer[*index] = pattern[i];
        ++*index;
    }
}

static void upc_draw_digits( char *buffer, int *index, char *digits, char isLeft ) {

    char temp[6][7];
    if ( isLeft ) {
        for( int i = 0; i < 6; ++i ) {
            memcpy(temp[i], UPC_DIGIT[digits[i]], sizeof( *UPC_DIGIT ) );
            upc_draw_pattern( buffer, index, temp[i], sizeof( *UPC_DIGIT ) );
        }
    }
    else {
        for( int i = 0; i < 6; ++i ) {
            memcpy(temp[i], UPC_DIGIT[digits[i + 6]], sizeof( *UPC_DIGIT ) );
            //invert values of RRRRRR digits
            for( int j = 0; j < sizeof( *UPC_DIGIT ); ++j ) {
                temp[i][j] = !temp[i][j];
            }
            upc_draw_pattern( buffer, index, temp[i], sizeof( *UPC_DIGIT ) );
        }
    }
}