Пример #1
0
static inline void
ean2ISSN(char *isn)
{
	unsigned	check;

	/* the number should come in this format: 977-0000-000-00-0 */
	/* Strip the first part, crop, and calculate the new check digit */
	hyphenate(isn, isn + 4, NULL, NULL);
	check = weight_checkdig(isn, 8);
	if (check == 10)
		isn[8] = 'X';
	else
		isn[8] = check + '0';
	isn[9] = '\0';
}
Пример #2
0
/*
 * ean2UPC/ISxN --- Convert in-place a normalized EAN13 string to the corresponding
 *					UPC/ISxN string number. Assumes the input string is normalized.
 */
static inline void
ean2ISBN(char *isn)
{
	char	   *aux;
	unsigned	check;

	/* the number should come in this format: 978-0-000-00000-0 */
	/* Strip the first part and calculate the new check digit */
	hyphenate(isn, isn + 4, NULL, NULL);
	check = weight_checkdig(isn, 10);
	aux = strchr(isn, '\0');
	while (!isdigit((unsigned char) *--aux));
	if (check == 10)
		*aux = 'X';
	else
		*aux = check + '0';
}
Пример #3
0
/*
 * ean2UPC/ISxN --- Convert in-place a normalized EAN13 string to the corresponding
 *					UPC/ISxN string number. Assumes the input string is normalized.
 */
static inline void
ean2ISBN(char *isn)
{
	char	   *aux;
	unsigned	check;

	/*
	 * The number should come in this format: 978-0-000-00000-0
	 * or may be an ISBN-13 number, 979-..., which does not have a short
	 * representation. Do the short output version if possible.
	 */
	if (strncmp("978-", isn, 4) == 0)
	{
		/* Strip the first part and calculate the new check digit */
		hyphenate(isn, isn + 4, NULL, NULL);
		check = weight_checkdig(isn, 10);
		aux = strchr(isn, '\0');
		while (!isdigit((unsigned char) *--aux));
		if (check == 10)
			*aux = 'X';
		else
			*aux = check + '0';
	}
}
Пример #4
0
/*
 * string2ean --- try to parse a string into an ean13.
 *
 * If errorOK is false, ereport a useful error message if the string is bad.
 * If errorOK is true, just return "false" for bad input.
 *
 * if the input string ends with '!' it will always be treated as invalid
 * (even if the check digit is valid)
 */
static bool
string2ean(const char *str, bool errorOK, ean13 *result,
		   enum isn_type accept)
{
	bool		digit,
				last;
	char		buf[17] = "                ";
	char	   *aux1 = buf + 3; /* leave space for the first part, in case
								 * it's needed */
	const char *aux2 = str;
	enum isn_type type = INVALID;
	unsigned	check = 0,
				rcheck = (unsigned) -1;
	unsigned	length = 0;
	bool		magic = false,
				valid = true;

	/* recognize and validate the number: */
	while (*aux2 && length <= 13)
	{
		last = (*(aux2 + 1) == '!' || *(aux2 + 1) == '\0');		/* is the last character */
		digit = (isdigit((unsigned char) *aux2) != 0);	/* is current character
														 * a digit? */
		if (*aux2 == '?' && last)		/* automagically calculate check digit
										 * if it's '?' */
			magic = digit = true;
		if (length == 0 && (*aux2 == 'M' || *aux2 == 'm'))
		{
			/* only ISMN can be here */
			if (type != INVALID)
				goto eaninvalid;
			type = ISMN;
			*aux1++ = 'M';
			length++;
		}
		else if (length == 7 && (digit || *aux2 == 'X' || *aux2 == 'x') && last)
		{
			/* only ISSN can be here */
			if (type != INVALID)
				goto eaninvalid;
			type = ISSN;
			*aux1++ = toupper((unsigned char) *aux2);
			length++;
		}
		else if (length == 9 && (digit || *aux2 == 'X' || *aux2 == 'x') && last)
		{
			/* only ISBN and ISMN can be here */
			if (type != INVALID && type != ISMN)
				goto eaninvalid;
			if (type == INVALID)
				type = ISBN;	/* ISMN must start with 'M' */
			*aux1++ = toupper((unsigned char) *aux2);
			length++;
		}
		else if (length == 11 && digit && last)
		{
			/* only UPC can be here */
			if (type != INVALID)
				goto eaninvalid;
			type = UPC;
			*aux1++ = *aux2;
			length++;
		}
		else if (*aux2 == '-' || *aux2 == ' ')
		{
			/* skip, we could validate but I think it's worthless */
		}
		else if (*aux2 == '!' && *(aux2 + 1) == '\0')
		{
			/* the invalid check digit sufix was found, set it */
			if (!magic)
				valid = false;
			magic = true;
		}
		else if (!digit)
		{
			goto eaninvalid;
		}
		else
		{
			*aux1++ = *aux2;
			if (++length > 13)
				goto eantoobig;
		}
		aux2++;
	}
	*aux1 = '\0';				/* terminate the string */

	/* find the current check digit value */
	if (length == 13)
	{
		/* only EAN13 can be here */
		if (type != INVALID)
			goto eaninvalid;
		type = EAN13;
		check = buf[15] - '0';
	}
	else if (length == 12)
	{
		/* only UPC can be here */
		if (type != UPC)
			goto eaninvalid;
		check = buf[14] - '0';
	}
	else if (length == 10)
	{
		if (type != ISBN && type != ISMN)
			goto eaninvalid;
		if (buf[12] == 'X')
			check = 10;
		else
			check = buf[12] - '0';
	}
	else if (length == 8)
	{
		if (type != INVALID && type != ISSN)
			goto eaninvalid;
		type = ISSN;
		if (buf[10] == 'X')
			check = 10;
		else
			check = buf[10] - '0';
	}
	else
		goto eaninvalid;

	if (type == INVALID)
		goto eaninvalid;

	/* obtain the real check digit value, validate, and convert to ean13: */
	if (accept == EAN13 && type != accept)
		goto eanwrongtype;
	if (accept != ANY && type != EAN13 && type != accept)
		goto eanwrongtype;
	switch (type)
	{
		case EAN13:
			valid = (valid && ((rcheck = checkdig(buf + 3, 13)) == check || magic));
			/* now get the subtype of EAN13: */
			if (buf[3] == '0')
				type = UPC;
			else if (strncmp("977", buf + 3, 3) == 0)
				type = ISSN;
			else if (strncmp("978", buf + 3, 3) == 0)
				type = ISBN;
			else if (strncmp("9790", buf + 3, 4) == 0)
				type = ISMN;
			else if (strncmp("979", buf + 3, 3) == 0)
				type = ISBN;
			if (accept != EAN13 && accept != ANY && type != accept)
				goto eanwrongtype;
			break;
		case ISMN:
			memcpy(buf, "9790", 4);		/* this isn't for sure yet, for now
										 * ISMN it's only 9790 */
			valid = (valid && ((rcheck = checkdig(buf, 13)) == check || magic));
			break;
		case ISBN:
			memcpy(buf, "978", 3);
			valid = (valid && ((rcheck = weight_checkdig(buf + 3, 10)) == check || magic));
			break;
		case ISSN:
			memcpy(buf + 10, "00", 2);	/* append 00 as the normal issue
										 * publication code */
			memcpy(buf, "977", 3);
			valid = (valid && ((rcheck = weight_checkdig(buf + 3, 8)) == check || magic));
			break;
		case UPC:
			buf[2] = '0';
			valid = (valid && ((rcheck = checkdig(buf + 2, 13)) == check || magic));
		default:
			break;
	}

	/* fix the check digit: */
	for (aux1 = buf; *aux1 && *aux1 <= ' '; aux1++);
	aux1[12] = checkdig(aux1, 13) + '0';
	aux1[13] = '\0';

	if (!valid && !magic)
		goto eanbadcheck;

	*result = str2ean(aux1);
	*result |= valid ? 0 : 1;
	return true;

eanbadcheck:
	if (g_weak)
	{							/* weak input mode is activated: */
		/* set the "invalid-check-digit-on-input" flag */
		*result = str2ean(aux1);
		*result |= 1;
		return true;
	}

	if (!errorOK)
	{
		if (rcheck == (unsigned) -1)
		{
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
					 errmsg("invalid %s number: \"%s\"",
							isn_names[accept], str)));
		}
		else
		{
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
			errmsg("invalid check digit for %s number: \"%s\", should be %c",
				   isn_names[accept], str, (rcheck == 10) ? ('X') : (rcheck + '0'))));
		}
	}
	return false;

eaninvalid:
	if (!errorOK)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
				 errmsg("invalid input syntax for %s number: \"%s\"",
						isn_names[accept], str)));
	return false;

eanwrongtype:
	if (!errorOK)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
				 errmsg("cannot cast %s to %s for number: \"%s\"",
						isn_names[type], isn_names[accept], str)));
	return false;

eantoobig:
	if (!errorOK)
		ereport(ERROR,
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
				 errmsg("value \"%s\" is out of range for %s type",
						str, isn_names[accept])));
	return false;
}