/*====================================================================* - Copyright (C) 2001 Leptonica. All rights reserved. - This software is distributed in the hope that it will be - useful, but with NO WARRANTY OF ANY KIND. - No author or distributor accepts responsibility to anyone for the - consequences of using this software, or for whether it serves any - particular purpose or works at all, unless he or she says so in - writing. Everyone is granted permission to copy, modify and - redistribute this source code, for commercial or non-commercial - purposes, with the following restrictions: (1) the origin of this - source code must not be misrepresented; (2) modified versions must - be plainly marked as such; and (3) this notice may not be removed - or altered from any source or modified source distribution. *====================================================================*/ /* * bardecode.c * * Dispatcher * char *barcodeDispatchDecoder() * * Format Determination * static l_int32 barcodeFindFormat() * l_int32 barcodeFormatIsSupported() * static l_int32 barcodeVerifyFormat() * * Decode 2 of 5 * static char *barcodeDecode2of5() * * Decode Interleaved 2 of 5 * static char *barcodeDecodeI2of5() * * Decode Code 93 * static char *barcodeDecode93() * * Decode Code 39 * static char *barcodeDecode39() * * Decode Codabar * static char *barcodeDecodeCodabar() * * Decode UPC-A * static char *barcodeDecodeUpca() * * Decode EAN 13 * static char *barcodeDecodeEan13() */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "allheaders.h" #include "readbarcode.h" static l_int32 barcodeFindFormat(char *barstr); static l_int32 barcodeVerifyFormat(char *barstr, l_int32 format, l_int32 *pvalid, l_int32 *preverse); static char *barcodeDecode2of5(char *barstr, l_int32 debugflag); static char *barcodeDecodeI2of5(char *barstr, l_int32 debugflag); static char *barcodeDecode93(char *barstr, l_int32 debugflag); static char *barcodeDecode39(char *barstr, l_int32 debugflag); static char *barcodeDecodeCodabar(char *barstr, l_int32 debugflag); static char *barcodeDecodeUpca(char *barstr, l_int32 debugflag); static char *barcodeDecodeEan13(char *barstr, l_int32 first, l_int32 debugflag); #ifndef NO_CONSOLE_IO #define DEBUG_CODES 0 #endif /* ~NO_CONSOLE_IO */ /*------------------------------------------------------------------------* * Decoding dispatcher * *------------------------------------------------------------------------*/ /*! * barcodeDispatchDecoder() * * Input: barstr (string of integers in set {1,2,3,4} of bar widths) * format (L_BF_ANY, L_BF_CODEI2OF5, L_BF_CODE93, ...) * debugflag (use 1 to generate debug output) * Return: data (string of decoded barcode data), or null on error */ char * barcodeDispatchDecoder(char *barstr, l_int32 format, l_int32 debugflag) { char *data = NULL; PROCNAME("barcodeDispatchDecoder"); if (!barstr) return (char *)ERROR_PTR("barstr not defined", procName, NULL); debugflag = FALSE; /* not used yet */ if (format == L_BF_ANY) format = barcodeFindFormat(barstr); if (format == L_BF_CODE2OF5) data = barcodeDecode2of5(barstr, debugflag); else if (format == L_BF_CODEI2OF5) data = barcodeDecodeI2of5(barstr, debugflag); else if (format == L_BF_CODE93) data = barcodeDecode93(barstr, debugflag); else if (format == L_BF_CODE39) data = barcodeDecode39(barstr, debugflag); else if (format == L_BF_CODABAR) data = barcodeDecodeCodabar(barstr, debugflag); else if (format == L_BF_UPCA) data = barcodeDecodeUpca(barstr, debugflag); else if (format == L_BF_EAN13) data = barcodeDecodeEan13(barstr, 0, debugflag); else return (char *)ERROR_PTR("format not implemented", procName, NULL); return data; } /*------------------------------------------------------------------------* * Barcode format determination * *------------------------------------------------------------------------*/ /*! * barcodeFindFormat() * * Input: barstr (of barcode widths, in set {1,2,3,4}) * Return: format (for barcode), or L_BF_UNKNOWN if not recognized */ static l_int32 barcodeFindFormat(char *barstr) { l_int32 i, format, valid; PROCNAME("barcodeFindFormat"); if (!barstr) return ERROR_INT("barstr not defined", procName, L_BF_UNKNOWN); for (i = 0; i < NumSupportedBarcodeFormats; i++) { format = SupportedBarcodeFormat[i]; barcodeVerifyFormat(barstr, format, &valid, NULL); if (valid) { L_INFO_STRING("Barcode format: %s", procName, SupportedBarcodeFormatName[i]); return format; } } return L_BF_UNKNOWN; } /*! * barcodeFormatIsSupported() * * Input: format * Return: 1 if format is one of those supported; 0 otherwise * */ l_int32 barcodeFormatIsSupported(l_int32 format) { l_int32 i; for (i = 0; i < NumSupportedBarcodeFormats; i++) { if (format == SupportedBarcodeFormat[i]) return 1; } return 0; } /*! * barcodeVerifyFormat() * * Input: barstr (of barcode widths, in set {1,2,3,4}) * format (L_BF_CODEI2OF5, L_BF_CODE93, ...) * &valid (<return> 0 if not valid, 1 and 2 if valid) * &reverse (<optional return> 1 if reversed; 0 otherwise) * Return: 0 if OK, 1 on error * * Notes: * (1) If valid == 1, the barcode is of the given format in the * forward order; if valid == 2, it is backwards. * (2) If the barcode needs to be reversed to read it, and &reverse * is provided, a 1 is put into @reverse. * (3) Add to this as more formats are supported. */ static l_int32 barcodeVerifyFormat(char *barstr, l_int32 format, l_int32 *pvalid, l_int32 *preverse) { char *revbarstr; l_int32 i, start, len, stop, mid; PROCNAME("barcodeVerifyFormat"); if (!pvalid) return ERROR_INT("barstr not defined", procName, 1); *pvalid = 0; if (preverse) *preverse = 0; if (!barstr) return ERROR_INT("barstr not defined", procName, 1); switch (format) { case L_BF_CODE2OF5: start = !strncmp(barstr, Code2of5[C25_START], 3); len = strlen(barstr); stop = !strncmp(&barstr[len - 5], Code2of5[C25_STOP], 5); if (start && stop) *pvalid = 1; else { revbarstr = stringReverse(barstr); start = !strncmp(revbarstr, Code2of5[C25_START], 3); stop = !strncmp(&revbarstr[len - 5], Code2of5[C25_STOP], 5); FREE(revbarstr); if (start && stop) { *pvalid = 1; if (preverse) *preverse = 1; } } break; case L_BF_CODEI2OF5: start = !strncmp(barstr, CodeI2of5[CI25_START], 4); len = strlen(barstr); stop = !strncmp(&barstr[len - 3], CodeI2of5[CI25_STOP], 3); if (start && stop) *pvalid = 1; else { revbarstr = stringReverse(barstr); start = !strncmp(revbarstr, CodeI2of5[CI25_START], 4); stop = !strncmp(&revbarstr[len - 3], CodeI2of5[CI25_STOP], 3); FREE(revbarstr); if (start && stop) { *pvalid = 1; if (preverse) *preverse = 1; } } break; case L_BF_CODE93: start = !strncmp(barstr, Code93[C93_START], 6); len = strlen(barstr); stop = !strncmp(&barstr[len - 7], Code93[C93_STOP], 6); if (start && stop) *pvalid = 1; else { revbarstr = stringReverse(barstr); start = !strncmp(revbarstr, Code93[C93_START], 6); stop = !strncmp(&revbarstr[len - 7], Code93[C93_STOP], 6); FREE(revbarstr); if (start && stop) { *pvalid = 1; if (preverse) *preverse = 1; } } break; case L_BF_CODE39: start = !strncmp(barstr, Code39[C39_START], 9); len = strlen(barstr); stop = !strncmp(&barstr[len - 9], Code39[C39_STOP], 9); if (start && stop) *pvalid = 1; else { revbarstr = stringReverse(barstr); start = !strncmp(revbarstr, Code39[C39_START], 9); stop = !strncmp(&revbarstr[len - 9], Code39[C39_STOP], 9); FREE(revbarstr); if (start && stop) { *pvalid = 1; if (preverse) *preverse = 1; } } break; case L_BF_CODABAR: start = stop = 0; len = strlen(barstr); for (i = 16; i <= 19; i++) /* any of these will do */ start += !strncmp(barstr, Codabar[i], 7); for (i = 16; i <= 19; i++) /* ditto */ stop += !strncmp(&barstr[len - 7], Codabar[i], 7); if (start && stop) *pvalid = 1; else { start = stop = 0; revbarstr = stringReverse(barstr); for (i = 16; i <= 19; i++) start += !strncmp(revbarstr, Codabar[i], 7); for (i = 16; i <= 19; i++) stop += !strncmp(&revbarstr[len - 7], Codabar[i], 7); FREE(revbarstr); if (start && stop) { *pvalid = 1; if (preverse) *preverse = 1; } } break; case L_BF_UPCA: case L_BF_EAN13: len = strlen(barstr); if (len == 59) { start = !strncmp(barstr, Upca[UPCA_START], 3); mid = !strncmp(&barstr[27], Upca[UPCA_MID], 5); stop = !strncmp(&barstr[len - 3], Upca[UPCA_STOP], 3); if (start && mid && stop) *pvalid = 1; } break; default: return ERROR_INT("format not supported", procName, 1); } return 0; } /*------------------------------------------------------------------------* * Code 2 of 5 * *------------------------------------------------------------------------*/ /*! * barcodeDecode2of5() * * Input: barstr (of widths, in set {1, 2}) * debugflag * Return: data (string of digits), or null if none found or on error * * Notes: * (1) Ref: http://en.wikipedia.org/wiki/Two-out-of-five_code (Note: * the codes given here are wrong!) * http://morovia.com/education/symbology/code25.asp * (2) This is a very low density encoding for the 10 digits. * Each digit is encoded with 5 black bars, of which 2 are wide * and 3 are narrow. No information is carried in the spaces * between the bars, which are all equal in width, represented by * a "1" in our encoding. * (3) The mapping from the sequence of five bar widths to the * digit is identical to the mapping used by the interleaved * 2 of 5 code. The start code is 21211, representing two * wide bars and a narrow bar, and the interleaved "1" spaces * are explicit. The stop code is 21112. For all codes * (including start and stop), the trailing space "1" is * implicit -- there is no reason to represent it in the * Code2of5[] array. */ static char * barcodeDecode2of5(char *barstr, l_int32 debugflag) { char *data, *vbarstr; char code[10]; l_int32 valid, reverse, i, j, len, error, ndigits, start, found; PROCNAME("barcodeDecodeI2of5"); if (!barstr) return (char *)ERROR_PTR("barstr not defined", procName, NULL); /* Verify format; reverse if necessary */ barcodeVerifyFormat(barstr, L_BF_CODE2OF5, &valid, &reverse); if (!valid) return (char *)ERROR_PTR("barstr not in 2of5 format", procName, NULL); if (reverse) vbarstr = stringReverse(barstr); else vbarstr = stringNew(barstr); /* Verify size */ len = strlen(vbarstr); if ((len - 11) % 10 != 0) return (char *)ERROR_PTR("size not divisible by 10: invalid 2of5 code", procName, NULL); error = FALSE; ndigits = (len - 11) / 10; data = (char *)CALLOC(ndigits + 1, sizeof(char)); memset(code, 0, 10); for (i = 0; i < ndigits; i++) { start = 6 + 10 * i; for (j = 0; j < 9; j++) code[j] = vbarstr[start + j]; if (debugflag) fprintf(stderr, "code: %s\n", code); found = FALSE; for (j = 0; j < 10; j++) { if (!strcmp(code, Code2of5[j])) { data[i] = 0x30 + j; found = TRUE; break; } } if (!found) error = TRUE; } FREE(vbarstr); if (error) { FREE(data); return (char *)ERROR_PTR("error in decoding", procName, NULL); } return data; } /*------------------------------------------------------------------------* * Interleaved Code 2 of 5 * *------------------------------------------------------------------------*/ /*! * barcodeDecodeI2of5() * * Input: barstr (of widths, in set {1, 2}) * debugflag * Return: data (string of digits), or null if none found or on error * * Notes: * (1) Ref: http://en.wikipedia.org/wiki/Interleaved_2_of_5 * (2) This always encodes an even number of digits. * The start code is 1111; the stop code is 211. */ static char * barcodeDecodeI2of5(char *barstr, l_int32 debugflag) { char *data, *vbarstr; char code1[6], code2[6]; l_int32 valid, reverse, i, j, len, error, npairs, start, found; PROCNAME("barcodeDecodeI2of5"); if (!barstr) return (char *)ERROR_PTR("barstr not defined", procName, NULL); /* Verify format; reverse if necessary */ barcodeVerifyFormat(barstr, L_BF_CODEI2OF5, &valid, &reverse); if (!valid) return (char *)ERROR_PTR("barstr not in i2of5 format", procName, NULL); if (reverse) vbarstr = stringReverse(barstr); else vbarstr = stringNew(barstr); /* Verify size */ len = strlen(vbarstr); if ((len - 7) % 10 != 0) return (char *)ERROR_PTR("size not divisible by 10: invalid I2of5 code", procName, NULL); error = FALSE; npairs = (len - 7) / 10; data = (char *)CALLOC(2 * npairs + 1, sizeof(char)); memset(code1, 0, 6); memset(code2, 0, 6); for (i = 0; i < npairs; i++) { start = 4 + 10 * i; for (j = 0; j < 5; j++) { code1[j] = vbarstr[start + 2 * j]; code2[j] = vbarstr[start + 2 * j + 1]; } if (debugflag) fprintf(stderr, "code1: %s, code2: %s\n", code1, code2); found = FALSE; for (j = 0; j < 10; j++) { if (!strcmp(code1, CodeI2of5[j])) { data[2 * i] = 0x30 + j; found = TRUE; break; } } if (!found) error = TRUE; found = FALSE; for (j = 0; j < 10; j++) { if (!strcmp(code2, CodeI2of5[j])) { data[2 * i + 1] = 0x30 + j; found = TRUE; break; } } if (!found) error = TRUE; } FREE(vbarstr); if (error) { FREE(data); return (char *)ERROR_PTR("error in decoding", procName, NULL); } return data; } /*------------------------------------------------------------------------* * Code 93 * *------------------------------------------------------------------------*/ /*! * barcodeDecode93() * * Input: barstr (of widths, in set {1, 2, 3, 4}) * debugflag * Return: data (string of digits), or null if none found or on error * * Notes: * (1) Ref: http://en.wikipedia.org/wiki/Code93 * http://morovia.com/education/symbology/code93.asp * (2) Each symbol has 3 black and 3 white bars. * The start and stop codes are 111141; the stop code then is * terminated with a final (1) bar. * (3) The last two codes are check codes. We are checking them * for correctness, and issuing a warning on failure. Should * probably not return any data on failure. */ static char * barcodeDecode93(char *barstr, l_int32 debugflag) { const char *checkc, *checkk; char *data, *vbarstr; char code[7]; l_int32 valid, reverse, i, j, len, error, nsymb, start, found, sum; l_int32 *index; PROCNAME("barcodeDecode93"); if (!barstr) return (char *)ERROR_PTR("barstr not defined", procName, NULL); /* Verify format; reverse if necessary */ barcodeVerifyFormat(barstr, L_BF_CODE93, &valid, &reverse); if (!valid) return (char *)ERROR_PTR("barstr not in code93 format", procName, NULL); if (reverse) vbarstr = stringReverse(barstr); else vbarstr = stringNew(barstr); /* Verify size; skip the first 6 and last 7 bars. */ len = strlen(vbarstr); if ((len - 13) % 6 != 0) return (char *)ERROR_PTR("size not divisible by 6: invalid code 93", procName, NULL); /* Decode the symbols */ nsymb = (len - 13) / 6; data = (char *)CALLOC(nsymb + 1, sizeof(char)); index = (l_int32 *)CALLOC(nsymb, sizeof(l_int32)); memset(code, 0, 7); error = FALSE; for (i = 0; i < nsymb; i++) { start = 6 + 6 * i; for (j = 0; j < 6; j++) code[j] = vbarstr[start + j]; if (debugflag) fprintf(stderr, "code: %s\n", code); found = FALSE; for (j = 0; j < C93_START; j++) { if (!strcmp(code, Code93[j])) { data[i] = Code93Val[j]; index[i] = j; found = TRUE; break; } } if (!found) error = TRUE; } FREE(vbarstr); if (error) { FREE(index); FREE(data); return (char *)ERROR_PTR("error in decoding", procName, NULL); } /* Do check sums. For character "C", use only the * actual data in computing the sum. For character "K", * use the actual data plus the check character "C". */ sum = 0; for (i = 0; i < nsymb - 2; i++) /* skip the "C" and "K" */ sum += ((i % 20) + 1) * index[nsymb - 3 - i]; if (data[nsymb - 2] != Code93Val[sum % 47]) L_WARNING("Error for check C", procName); if (debugflag) { checkc = Code93[sum % 47]; fprintf(stderr, "checkc = %s\n", checkc); } sum = 0; for (i = 0; i < nsymb - 1; i++) /* skip the "K" */ sum += ((i % 15) + 1) * index[nsymb - 2 - i]; if (data[nsymb - 1] != Code93Val[sum % 47]) L_WARNING("Error for check K", procName); if (debugflag) { checkk = Code93[sum % 47]; fprintf(stderr, "checkk = %s\n", checkk); } /* Remove the two check codes from the output */ data[nsymb - 2] = '\0'; FREE(index); return data; } /*------------------------------------------------------------------------* * Code 39 * *------------------------------------------------------------------------*/ /*! * barcodeDecode39() * * Input: barstr (of widths, in set {1, 2}) * debugflag * Return: data (string of digits), or null if none found or on error * * Notes: * (1) Ref: http://en.wikipedia.org/wiki/Code39 * http://morovia.com/education/symbology/code39.asp * (2) Each symbol has 5 black and 4 white bars. * The start and stop codes are 121121211 (the asterisk) * (3) This decoder was contributed by Roger Hyde. */ static char * barcodeDecode39(char *barstr, l_int32 debugflag) { char *data, *vbarstr; char code[10]; l_int32 valid, reverse, i, j, len, error, nsymb, start, found; PROCNAME("barcodeDecode39"); if (!barstr) return (char *)ERROR_PTR("barstr not defined", procName, NULL); /* Verify format; reverse if necessary */ barcodeVerifyFormat(barstr, L_BF_CODE39, &valid, &reverse); if (!valid) return (char *)ERROR_PTR("barstr not in code39 format", procName, NULL); if (reverse) vbarstr = stringReverse(barstr); else vbarstr = stringNew(barstr); /* Verify size */ len = strlen(vbarstr); if ((len + 1) % 10 != 0) return (char *)ERROR_PTR("size+1 not divisible by 10: invalid code 39", procName, NULL); /* Decode the symbols */ nsymb = (len - 19) / 10; data = (char *)CALLOC(nsymb + 1, sizeof(char)); memset(code, 0, 10); error = FALSE; for (i = 0; i < nsymb; i++) { start = 10 + 10 * i; for (j = 0; j < 9; j++) code[j] = vbarstr[start + j]; if (debugflag) fprintf(stderr, "code: %s\n", code); found = FALSE; for (j = 0; j < C39_START; j++) { if (!strcmp(code, Code39[j])) { data[i] = Code39Val[j]; found = TRUE; break; } } if (!found) error = TRUE; } FREE(vbarstr); if (error) { FREE(data); return (char *)ERROR_PTR("error in decoding", procName, NULL); } return data; } /*------------------------------------------------------------------------* * Codabar * *------------------------------------------------------------------------*/ /*! * barcodeDecodeCodabar() * * Input: barstr (of widths, in set {1, 2}) * debugflag * Return: data (string of digits), or null if none found or on error * * Notes: * (1) Ref: http://en.wikipedia.org/wiki/Codabar * http://morovia.com/education/symbology/codabar.asp * (2) Each symbol has 4 black and 3 white bars. They represent the * 10 digits, and optionally 6 other characters. The start and * stop codes can be any of four (typically denoted A,B,C,D). */ static char * barcodeDecodeCodabar(char *barstr, l_int32 debugflag) { char *data, *vbarstr; char code[8]; l_int32 valid, reverse, i, j, len, error, nsymb, start, found; PROCNAME("barcodeDecodeCodabar"); if (!barstr) return (char *)ERROR_PTR("barstr not defined", procName, NULL); /* Verify format; reverse if necessary */ barcodeVerifyFormat(barstr, L_BF_CODABAR, &valid, &reverse); if (!valid) return (char *)ERROR_PTR("barstr not in codabar format", procName, NULL); if (reverse) vbarstr = stringReverse(barstr); else vbarstr = stringNew(barstr); /* Verify size */ len = strlen(vbarstr); if ((len + 1) % 8 != 0) return (char *)ERROR_PTR("size+1 not divisible by 8: invalid codabar", procName, NULL); /* Decode the symbols */ nsymb = (len - 15) / 8; data = (char *)CALLOC(nsymb + 1, sizeof(char)); memset(code, 0, 8); error = FALSE; for (i = 0; i < nsymb; i++) { start = 8 + 8 * i; for (j = 0; j < 7; j++) code[j] = vbarstr[start + j]; if (debugflag) fprintf(stderr, "code: %s\n", code); found = FALSE; for (j = 0; j < 16; j++) { if (!strcmp(code, Codabar[j])) { data[i] = CodabarVal[j]; found = TRUE; break; } } if (!found) error = TRUE; } FREE(vbarstr); if (error) { FREE(data); return (char *)ERROR_PTR("error in decoding", procName, NULL); } return data; } /*------------------------------------------------------------------------* * Code UPC-A * *------------------------------------------------------------------------*/ /*! * barcodeDecodeUpca() * * Input: barstr (of widths, in set {1, 2, 3, 4}) * debugflag * Return: data (string of digits), or null if none found or on error * * Notes: * (1) Ref: http://en.wikipedia.org/wiki/UniversalProductCode * http://morovia.com/education/symbology/upc-a.asp * (2) Each symbol has 2 black and 2 white bars, and encodes a digit. * The start and stop codes are 111 and 111. There are a total of * 30 black bars, encoding 12 digits in two sets of 6, with * 2 black bars separating the sets. * (3) The last digit is a check digit. We check for correctness, and * issue a warning on failure. Should probably not return any * data on failure. */ static char * barcodeDecodeUpca(char *barstr, l_int32 debugflag) { char *data, *vbarstr; char code[5]; l_int32 valid, i, j, len, error, start, found, sum, checkdigit; PROCNAME("barcodeDecodeUpca"); if (!barstr) return (char *)ERROR_PTR("barstr not defined", procName, NULL); /* Verify format; reverse has no meaning here -- we must test both */ barcodeVerifyFormat(barstr, L_BF_UPCA, &valid, NULL); if (!valid) return (char *)ERROR_PTR("barstr not in UPC-A format", procName, NULL); /* Verify size */ len = strlen(barstr); if (len != 59) return (char *)ERROR_PTR("size not 59; invalid UPC-A barcode", procName, NULL); /* Check the first digit. If invalid, reverse the string. */ memset(code, 0, 5); for (i = 0; i < 4; i++) code[i] = barstr[i + 3]; found = FALSE; for (i = 0; i < 10; i++) { if (!strcmp(code, Upca[i])) { found = TRUE; break; } } if (found == FALSE) vbarstr = stringReverse(barstr); else vbarstr = stringNew(barstr); /* Decode the 12 symbols */ data = (char *)CALLOC(13, sizeof(char)); memset(code, 0, 5); error = FALSE; for (i = 0; i < 12; i++) { if (i < 6) start = 3 + 4 * i; else start = 32 + 4 * (i - 6); for (j = 0; j < 4; j++) code[j] = vbarstr[start + j]; if (debugflag) fprintf(stderr, "code: %s\n", code); found = FALSE; for (j = 0; j < 10; j++) { if (!strcmp(code, Upca[j])) { data[i] = 0x30 + j; found = TRUE; break; } } if (!found) error = TRUE; } FREE(vbarstr); if (error) { FREE(data); return (char *)ERROR_PTR("error in decoding", procName, NULL); } /* Calculate the check digit (data[11]). */ sum = 0; for (i = 0; i < 12; i += 2) /* "even" digits */ sum += 3 * (data[i] - 0x30); for (i = 1; i < 11; i += 2) /* "odd" digits */ sum += (data[i] - 0x30); checkdigit = sum % 10; if (checkdigit) /* not 0 */ checkdigit = 10 - checkdigit; if (checkdigit + 0x30 != data[11]) L_WARNING("Error for UPC-A check character", procName); return data; } /*------------------------------------------------------------------------* * Code EAN-13 * *------------------------------------------------------------------------*/ /*! * barcodeDecodeEan13() * * Input: barstr (of widths, in set {1, 2, 3, 4}) * first (first digit: 0 - 9) * debugflag * Return: data (string of digits), or null if none found or on error * * Notes: * (1) Ref: http://en.wikipedia.org/wiki/UniversalProductCode * http://morovia.com/education/symbology/ean-13.asp * (2) The encoding is essentially the same as UPC-A, except * there are 13 digits in total, of which 12 are encoded * by bars (as with UPC-A) and the 13th is a leading digit * that determines the encoding of the next 6 digits, * selecting each digit from one of two tables. * encoded in the bars (as with UPC-A). If the first digit * is 0, the encoding is identical to UPC-A. * (3) As with UPC-A, the last digit is a check digit. * (4) For now, we assume the first digit is input to this function. * Eventually, we will read it by pattern matching. * * TODO: fix this for multiple tables, depending on the value of @first */ static char * barcodeDecodeEan13(char *barstr, l_int32 first, l_int32 debugflag) { char *data, *vbarstr; char code[5]; l_int32 valid, i, j, len, error, start, found, sum, checkdigit; PROCNAME("barcodeDecodeEan13"); if (!barstr) return (char *)ERROR_PTR("barstr not defined", procName, NULL); /* Verify format. You can't tell the orientation by the start * and stop codes, but you can by the location of the digits. * Use the UPCA verifier for EAN 13 -- it is identical. */ barcodeVerifyFormat(barstr, L_BF_UPCA, &valid, NULL); if (!valid) return (char *)ERROR_PTR("barstr not in EAN 13 format", procName, NULL); /* Verify size */ len = strlen(barstr); if (len != 59) return (char *)ERROR_PTR("size not 59; invalid EAN 13 barcode", procName, NULL); /* Check the first digit. If invalid, reverse the string. */ memset(code, 0, 5); for (i = 0; i < 4; i++) code[i] = barstr[i + 3]; found = FALSE; for (i = 0; i < 10; i++) { if (!strcmp(code, Upca[i])) { found = TRUE; break; } } if (found == FALSE) vbarstr = stringReverse(barstr); else vbarstr = stringNew(barstr); /* Decode the 12 symbols */ data = (char *)CALLOC(13, sizeof(char)); memset(code, 0, 5); error = FALSE; for (i = 0; i < 12; i++) { if (i < 6) start = 3 + 4 * i; else start = 32 + 4 * (i - 6); for (j = 0; j < 4; j++) code[j] = vbarstr[start + j]; if (debugflag) fprintf(stderr, "code: %s\n", code); found = FALSE; for (j = 0; j < 10; j++) { if (!strcmp(code, Upca[j])) { data[i] = 0x30 + j; found = TRUE; break; } } if (!found) error = TRUE; } FREE(vbarstr); if (error) { FREE(data); return (char *)ERROR_PTR("error in decoding", procName, NULL); } /* Calculate the check digit (data[11]). */ sum = 0; for (i = 0; i < 12; i += 2) /* "even" digits */ sum += 3 * (data[i] - 0x30); for (i = 1; i < 12; i += 2) /* "odd" digits */ sum += (data[i] - 0x30); checkdigit = sum % 10; if (checkdigit) /* not 0 */ checkdigit = 10 - checkdigit; if (checkdigit + 0x30 != data[11]) L_WARNING("Error for EAN-13 check character", procName); return data; }