bsw/jbe@1309: local oddmap = { bsw/jbe@1309: [0] = 1, 0, 5, 7, 9, 13, 15, 17, 19, 21, bsw/jbe@1309: 2, 4, 18, 20, 11, 3, 6, 8, 12, 14, 16, bsw/jbe@1309: 10, 22, 25, 24, 23 bsw/jbe@1309: } bsw/jbe@1309: bsw/jbe@1309: local monthtable = { bsw/jbe@1309: "A", "B", "C", "D", "E", "H", "L", "M", "P", "R", "S", "T" bsw/jbe@1309: } bsw/jbe@1309: bsw/jbe@1309: local function removeaccent(str) bsw/jbe@1309: local gsub = string.gsub bsw/jbe@1309: str = gsub(str, "\195\129", "A") bsw/jbe@1309: str = gsub(str, "\195\128", "A") bsw/jbe@1309: str = gsub(str, "\195\161", "a") bsw/jbe@1309: str = gsub(str, "\195\160", "a") bsw/jbe@1309: str = gsub(str, "\195\137", "E") bsw/jbe@1309: str = gsub(str, "\195\136", "E") bsw/jbe@1309: str = gsub(str, "\195\169", "e") bsw/jbe@1309: str = gsub(str, "\195\168", "e") bsw/jbe@1309: str = gsub(str, "\195\141", "I") bsw/jbe@1309: str = gsub(str, "\195\140", "I") bsw/jbe@1309: str = gsub(str, "\195\173", "i") bsw/jbe@1309: str = gsub(str, "\195\172", "i") bsw/jbe@1309: str = gsub(str, "\195\147", "O") bsw/jbe@1309: str = gsub(str, "\195\146", "O") bsw/jbe@1309: str = gsub(str, "\195\179", "o") bsw/jbe@1309: str = gsub(str, "\195\178", "o") bsw/jbe@1309: str = gsub(str, "\195\154", "U") bsw/jbe@1309: str = gsub(str, "\195\153", "U") bsw/jbe@1309: str = gsub(str, "\195\186", "u") bsw/jbe@1309: str = gsub(str, "\195\185", "u") bsw/jbe@1309: return str bsw/jbe@1309: end bsw/jbe@1309: bsw/jbe@1309: local function normalize_name(str) bsw/jbe@1309: local gsub = string.gsub bsw/jbe@1309: str = removeaccent(str) bsw/jbe@1309: str = gsub(str, " ", "") bsw/jbe@1309: str = gsub(str, "-", "") bsw/jbe@1309: str = gsub(str, "'", "") bsw/jbe@1309: str = gsub(str, "\226\128\146", "") bsw/jbe@1309: str = gsub(str, "\226\128\147", "") bsw/jbe@1309: str = gsub(str, "\226\128\148", "") bsw/jbe@1309: if string.find(str, "^[A-Za-z]+$") then bsw/jbe@1309: return string.upper(str) bsw/jbe@1309: else bsw/jbe@1309: return nil bsw/jbe@1309: end bsw/jbe@1309: end bsw/jbe@1309: bsw/jbe@1309: local function remove_consonants(str) bsw/jbe@1309: return (string.gsub(str, "[BCDFGHJKLMNPQRSTVWXYZ]", "")) bsw/jbe@1309: end bsw/jbe@1309: bsw/jbe@1309: local function remove_vowels(str) bsw/jbe@1309: return (string.gsub(str, "[AEIOU]", "")) bsw/jbe@1309: end bsw/jbe@1309: bsw/jbe@1309: local function numberize(str) bsw/jbe@1309: local gsub = string.gsub bsw/jbe@1309: str = gsub(str, "L", "0") bsw/jbe@1309: str = gsub(str, "M", "1") bsw/jbe@1309: str = gsub(str, "N", "2") bsw/jbe@1309: str = gsub(str, "P", "3") bsw/jbe@1309: str = gsub(str, "Q", "4") bsw/jbe@1309: str = gsub(str, "R", "5") bsw/jbe@1309: str = gsub(str, "S", "6") bsw/jbe@1309: str = gsub(str, "T", "7") bsw/jbe@1309: str = gsub(str, "U", "8") bsw/jbe@1309: str = gsub(str, "V", "9") bsw/jbe@1309: return str bsw/jbe@1309: end bsw/jbe@1309: bsw/jbe@1309: return function(code, data) bsw/jbe@1309: local sub = string.sub bsw/jbe@1309: local byte = string.byte bsw/jbe@1309: local byte0 = byte("0") bsw/jbe@1309: local byteA = byte("A") bsw/jbe@1309: local function byteat(str, pos) bsw/jbe@1309: return (byte(sub(str, pos, pos))) bsw/jbe@1309: end bsw/jbe@1309: if #code ~= 16 then bsw/jbe@1309: return false, "Invalid length" bsw/jbe@1309: end bsw/jbe@1309: local sum = 0 bsw/jbe@1309: for i = 1, 15, 2 do bsw/jbe@1309: local b = byteat(code, i) bsw/jbe@1309: local b0 = b - byte0 bsw/jbe@1309: if b0 >= 0 and b0 <= 9 then bsw/jbe@1309: sum = sum + oddmap[b0] bsw/jbe@1309: else bsw/jbe@1309: local bA = b - byteA bsw/jbe@1309: if bA >= 0 and bA <= 25 then bsw/jbe@1309: sum = sum + oddmap[bA] bsw/jbe@1309: else bsw/jbe@1309: return false, "Invalid character" bsw/jbe@1309: end bsw/jbe@1309: end bsw/jbe@1309: end bsw/jbe@1309: for i = 2, 14, 2 do bsw/jbe@1309: local b = byteat(code, i) bsw/jbe@1309: local b0 = b - byte0 bsw/jbe@1309: if b0 >= 0 and b0 <= 9 then bsw/jbe@1309: sum = sum + b0 bsw/jbe@1309: else bsw/jbe@1309: local bA = b - byteA bsw/jbe@1309: if bA >= 0 and bA <= 25 then bsw/jbe@1309: sum = sum + bA bsw/jbe@1309: else bsw/jbe@1309: return false, "Invalid character" bsw/jbe@1309: end bsw/jbe@1309: end bsw/jbe@1309: end bsw/jbe@1309: local check = byteat(code, 16) bsw/jbe@1309: local checkA = check - byteA bsw/jbe@1309: if checkA >= 0 and checkA <= 25 then bsw/jbe@1309: if checkA ~= sum % 26 then bsw/jbe@1309: return false, "Invalid checksum" bsw/jbe@1309: end bsw/jbe@1309: else bsw/jbe@1309: local check0 = check - byte0 bsw/jbe@1309: if check0 >= 0 and check0 <= 9 then bsw/jbe@1309: return false, "Checksum must not be numeric" bsw/jbe@1309: else bsw/jbe@1309: return false, "Invalid character" bsw/jbe@1309: end bsw/jbe@1309: end bsw/jbe@1309: if data then bsw/jbe@1309: if data.last_name then bsw/jbe@1309: local name = normalize_name(data.last_name) bsw/jbe@1309: if not name then bsw/jbe@1309: return false, "Invalid last name" bsw/jbe@1309: end bsw/jbe@1309: local consonants = remove_vowels(name) bsw/jbe@1309: local short = sub(consonants, 1, 3) bsw/jbe@1309: if #short < 3 then bsw/jbe@1309: local vowels = remove_consonants(name) bsw/jbe@1309: short = short .. sub(vowels, 1, 3 - #short) bsw/jbe@1309: while #short < 3 do bsw/jbe@1309: short = short .. "X" bsw/jbe@1309: end bsw/jbe@1309: end bsw/jbe@1309: if short ~= sub(code, 1, 3) then bsw/jbe@1309: return false, "Last name not matching" bsw/jbe@1309: end bsw/jbe@1309: end bsw/jbe@1309: if data.first_name then bsw/jbe@1309: local name = normalize_name(data.first_name) bsw/jbe@1309: if not name then bsw/jbe@1309: return false, "Invalid first name" bsw/jbe@1309: end bsw/jbe@1309: local consonants = remove_vowels(name) bsw/jbe@1309: local short bsw/jbe@1309: if #consonants >= 4 then bsw/jbe@1309: short = sub(consonants, 1, 1) .. sub(consonants, 3, 4) bsw/jbe@1309: else bsw/jbe@1309: short = consonants bsw/jbe@1309: if #short < 3 then bsw/jbe@1309: local vowels = remove_consonants(name) bsw/jbe@1309: short = short .. sub(vowels, 1, 3 - #short) bsw/jbe@1309: while #short < 3 do bsw/jbe@1309: short = short .. "X" bsw/jbe@1309: end bsw/jbe@1309: end bsw/jbe@1309: end bsw/jbe@1309: if short ~= sub(code, 4, 6) then bsw/jbe@1309: return false, "First name not matching" bsw/jbe@1309: end bsw/jbe@1309: end bsw/jbe@1309: if data.year then bsw/jbe@1309: local year = tostring(data.year % 100) bsw/jbe@1309: if #year < 2 then bsw/jbe@1309: year = "0" .. year bsw/jbe@1309: end bsw/jbe@1309: if year ~= numberize(sub(code, 7, 8)) then bsw/jbe@1309: return false, "Year of birth not matching" bsw/jbe@1309: end bsw/jbe@1309: end bsw/jbe@1309: if data.month then bsw/jbe@1309: local monthchar = monthtable[data.month] bsw/jbe@1309: if monthchar ~= sub(code, 9, 9) then bsw/jbe@1309: return false, "Month of birth not matching" bsw/jbe@1309: end bsw/jbe@1309: end bsw/jbe@1309: if data.day then bsw/jbe@1309: local day = tostring(data.day) bsw/jbe@1309: if #day < 2 then bsw/jbe@1309: day = "0" .. day bsw/jbe@1309: end bsw/jbe@1309: local daycode = numberize(sub(code, 10, 11)) bsw/jbe@1309: if day ~= daycode and tostring(day + 40) ~= daycode then bsw/jbe@1309: return false, "Day of birth not matching" bsw/jbe@1309: end bsw/jbe@1309: end bsw/jbe@1309: end bsw/jbe@1309: return true bsw/jbe@1309: end