2023-01-21 18:31:50 +00:00
|
|
|
/*
|
|
|
|
* SPDX-FileCopyrightText: 2023 jordi fita mas <jfita@peritasoft.com>
|
|
|
|
*
|
2023-01-21 19:04:31 +00:00
|
|
|
* SPDX-License-Identifier: PostgreSQL
|
2023-01-21 18:31:50 +00:00
|
|
|
*/
|
|
|
|
#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] * 2;
|
|
|
|
int a = d / 10;
|
|
|
|
int b = d % 10;
|
|
|
|
odds += a + b;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
checksum = 10 - (odds + evens) % 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);
|
|
|
|
}
|
|
|
|
|