vat/es.c

149 lines
2.3 KiB
C

/*
* SPDX-FileCopyrightText: 2023 jordi fita mas <jfita@peritasoft.com>
*
* SPDX-License-Identifier: PostgreSQL
*/
#include "es.h"
#include <stdbool.h>
#include <ctype.h>
#include <postgres.h>
#include <utils/palloc.h>
static char
compute_dni_check_digit(const char *start, const char *end)
{
unsigned long int n = 0;
const char *p = start;
for(; p != end; p++) {
n = n * 10 + *p - 48;
}
return "TRWAGMYFPDXBNJZSQVHLCKE"[n % 23];
}
static bool
valid_short_dni(const char *dni) {
return dni[8] == compute_dni_check_digit(dni + 1, dni + 8);
}
static bool
valid_dni(const char *dni) {
return dni[8] == compute_dni_check_digit(dni, dni + 8);
}
static bool
valid_nie(char *nie) {
bool valid = false;
nie[0] -= 'X' - 48;
valid = nie[8] == compute_dni_check_digit(nie, nie + 8);
nie[0] += 'X' - 48;
return valid;
}
static bool
valid_cif(const char *cif) {
int odds = 0;
int evens = 0;
int n = 0;
int checksum;
for (n = 1; n < 8; n++) {
if (n % 2 == 0) {
evens += cif[n] - 48;
} else {
int d = (cif[n] - 48) * 2;
int a = d / 10;
int b = d % 10;
odds += a + b;
}
}
checksum = (10 - (odds + evens) % 10) % 10;
return cif[8] == checksum + 48 || cif[8] == "JABCDEFGHI"[checksum];
}
char *
check_es_vat(const char *str, size_t len) {
const char *p = str;
const char *end = p + len;
char buf[10] = { 0 };
int n = 0;
if (len < 9 ) {
return NULL;
}
for (; p != end && n < 10; p++) {
char c = *p;
if (c == ' ' || c == '-') continue;
if (n > 0 && n < 8) {
if (!isdigit(c)) {
return NULL;
}
buf[n] = c;
} else {
buf[n] = toupper(c);
}
n++;
}
if (n == 10) {
return NULL;
}
buf[9] = 0;
switch (buf[0]) {
case 'K':
case 'L':
case 'M':
if (!valid_short_dni(buf)) {
return NULL;
}
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (!valid_dni(buf)) {
return NULL;
}
break;
case 'X':
case 'Y':
case 'Z':
if (!valid_nie(buf)) {
return NULL;
}
break;
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
case 'G':
case 'H':
case 'J':
case 'N':
case 'P':
case 'Q':
case 'R':
case 'S':
case 'U':
case 'V':
case 'W':
if (!valid_cif(buf)) {
return NULL;
}
break;
default:
return NULL;
}
return pstrdup(buf);
}