/*====================================================================* - Copyright (C) 2001 Leptonica. All rights reserved. - - 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. - - 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 ANY - 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. *====================================================================*/ /*! * \file 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() **/ #ifdef HAVE_CONFIG_H #include
* 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) Require at least 12 data bits, in addition to format identifiers. * (TODO) If the barcode has a fixed length, this should be used * explicitly, as is done for L_BF_UPCA and L_BF_EAN13. * (4) (TODO) 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); if (len < 20) return ERROR_INT("barstr too short for CODE2OF5", procName, 1); 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); LEPT_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); if (len < 20) return ERROR_INT("barstr too short for CODEI2OF5", procName, 1); 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); LEPT_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); if (len < 28) return ERROR_INT("barstr too short for CODE93", procName, 1); 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); LEPT_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); if (len < 30) return ERROR_INT("barstr too short for CODE39", procName, 1); 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); LEPT_FREE(revbarstr); if (start && stop) { *pvalid = 1; if (preverse) *preverse = 1; } } break; case L_BF_CODABAR: start = stop = 0; len = strlen(barstr); if (len < 26) return ERROR_INT("barstr too short for CODABAR", procName, 1); 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); LEPT_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) return ERROR_INT("invalid length for UPCA or EAN13", procName, 1); 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 * *------------------------------------------------------------------------*/ /*! * \brief barcodeDecode2of5() * * \param[in] barstr of widths, in set {1, 2} * \param[in] 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) { LEPT_FREE(vbarstr); return (char *)ERROR_PTR("size not divisible by 10: invalid 2of5 code", procName, NULL); } error = FALSE; ndigits = (len - 11) / 10; data = (char *)LEPT_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) lept_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; } LEPT_FREE(vbarstr); if (error) { LEPT_FREE(data); return (char *)ERROR_PTR("error in decoding", procName, NULL); } return data; } /*------------------------------------------------------------------------* * Interleaved Code 2 of 5 * *------------------------------------------------------------------------*/ /*! * \brief barcodeDecodeI2of5() * * \param[in] barstr of widths, in set {1, 2} * \param[in] 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) { LEPT_FREE(vbarstr); return (char *)ERROR_PTR("size not divisible by 10: invalid I2of5 code", procName, NULL); } error = FALSE; npairs = (len - 7) / 10; data = (char *)LEPT_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) lept_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; } LEPT_FREE(vbarstr); if (error) { LEPT_FREE(data); return (char *)ERROR_PTR("error in decoding", procName, NULL); } return data; } /*------------------------------------------------------------------------* * Code 93 * *------------------------------------------------------------------------*/ /*! * \brief barcodeDecode93() * * \param[in] barstr of widths, in set {1, 2, 3, 4} * \param[in] 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) { LEPT_FREE(vbarstr); return (char *)ERROR_PTR("size not divisible by 6: invalid code 93", procName, NULL); } /* Decode the symbols */ nsymb = (len - 13) / 6; data = (char *)LEPT_CALLOC(nsymb + 1, sizeof(char)); index = (l_int32 *)LEPT_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) lept_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; } LEPT_FREE(vbarstr); if (error) { LEPT_FREE(index); LEPT_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\n", procName); if (debugflag) { checkc = Code93[sum % 47]; lept_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\n", procName); if (debugflag) { checkk = Code93[sum % 47]; lept_stderr("checkk = %s\n", checkk); } /* Remove the two check codes from the output */ data[nsymb - 2] = '\0'; LEPT_FREE(index); return data; } /*------------------------------------------------------------------------* * Code 39 * *------------------------------------------------------------------------*/ /*! * \brief barcodeDecode39() * * \param[in] barstr of widths, in set {1, 2} * \param[in] 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) { LEPT_FREE(vbarstr); return (char *)ERROR_PTR("size+1 not divisible by 10: invalid code 39", procName, NULL); } /* Decode the symbols */ nsymb = (len - 19) / 10; data = (char *)LEPT_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) lept_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; } LEPT_FREE(vbarstr); if (error) { LEPT_FREE(data); return (char *)ERROR_PTR("error in decoding", procName, NULL); } return data; } /*------------------------------------------------------------------------* * Codabar * *------------------------------------------------------------------------*/ /*! * \brief barcodeDecodeCodabar() * * \param[in] barstr of widths, in set {1, 2} * \param[in] 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) { LEPT_FREE(vbarstr); return (char *)ERROR_PTR("size+1 not divisible by 8: invalid codabar", procName, NULL); } /* Decode the symbols */ nsymb = (len - 15) / 8; data = (char *)LEPT_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) lept_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; } LEPT_FREE(vbarstr); if (error) { LEPT_FREE(data); return (char *)ERROR_PTR("error in decoding", procName, NULL); } return data; } /*------------------------------------------------------------------------* * Code UPC-A * *------------------------------------------------------------------------*/ /*! * \brief barcodeDecodeUpca() * * \param[in] barstr of widths, in set {1, 2, 3, 4} * \param[in] 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 *)LEPT_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) lept_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; } LEPT_FREE(vbarstr); if (error) { LEPT_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\n", procName); return data; } /*------------------------------------------------------------------------* * Code EAN-13 * *------------------------------------------------------------------------*/ /*! * \brief barcodeDecodeEan13() * * \param[in] barstr of widths, in set {1, 2, 3, 4} * \param[in] first first digit: 0 - 9 * \param[in] 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 *)LEPT_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) lept_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; } LEPT_FREE(vbarstr); if (error) { LEPT_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\n", procName); return data; }