| rev | 
   line source | 
| 
bsw/jbe@1309
 | 
     1 local oddmap = {
 | 
| 
bsw/jbe@1309
 | 
     2   [0] = 1, 0, 5, 7, 9, 13, 15, 17, 19, 21,
 | 
| 
bsw/jbe@1309
 | 
     3   2, 4, 18, 20, 11, 3, 6, 8, 12, 14, 16,
 | 
| 
bsw/jbe@1309
 | 
     4   10, 22, 25, 24, 23
 | 
| 
bsw/jbe@1309
 | 
     5 }
 | 
| 
bsw/jbe@1309
 | 
     6 
 | 
| 
bsw/jbe@1309
 | 
     7 local monthtable = {
 | 
| 
bsw/jbe@1309
 | 
     8   "A", "B", "C", "D", "E", "H", "L", "M", "P", "R", "S", "T"
 | 
| 
bsw/jbe@1309
 | 
     9 }
 | 
| 
bsw/jbe@1309
 | 
    10 
 | 
| 
bsw/jbe@1309
 | 
    11 local function removeaccent(str)
 | 
| 
bsw/jbe@1309
 | 
    12   local gsub = string.gsub
 | 
| 
bsw/jbe@1309
 | 
    13   str = gsub(str, "\195\129", "A")
 | 
| 
bsw/jbe@1309
 | 
    14   str = gsub(str, "\195\128", "A")
 | 
| 
bsw/jbe@1309
 | 
    15   str = gsub(str, "\195\161", "a")
 | 
| 
bsw/jbe@1309
 | 
    16   str = gsub(str, "\195\160", "a")
 | 
| 
bsw/jbe@1309
 | 
    17   str = gsub(str, "\195\137", "E")
 | 
| 
bsw/jbe@1309
 | 
    18   str = gsub(str, "\195\136", "E")
 | 
| 
bsw/jbe@1309
 | 
    19   str = gsub(str, "\195\169", "e")
 | 
| 
bsw/jbe@1309
 | 
    20   str = gsub(str, "\195\168", "e")
 | 
| 
bsw/jbe@1309
 | 
    21   str = gsub(str, "\195\141", "I")
 | 
| 
bsw/jbe@1309
 | 
    22   str = gsub(str, "\195\140", "I")
 | 
| 
bsw/jbe@1309
 | 
    23   str = gsub(str, "\195\173", "i")
 | 
| 
bsw/jbe@1309
 | 
    24   str = gsub(str, "\195\172", "i")
 | 
| 
bsw/jbe@1309
 | 
    25   str = gsub(str, "\195\147", "O")
 | 
| 
bsw/jbe@1309
 | 
    26   str = gsub(str, "\195\146", "O")
 | 
| 
bsw/jbe@1309
 | 
    27   str = gsub(str, "\195\179", "o")
 | 
| 
bsw/jbe@1309
 | 
    28   str = gsub(str, "\195\178", "o")
 | 
| 
bsw/jbe@1309
 | 
    29   str = gsub(str, "\195\154", "U")
 | 
| 
bsw/jbe@1309
 | 
    30   str = gsub(str, "\195\153", "U")
 | 
| 
bsw/jbe@1309
 | 
    31   str = gsub(str, "\195\186", "u")
 | 
| 
bsw/jbe@1309
 | 
    32   str = gsub(str, "\195\185", "u")
 | 
| 
bsw/jbe@1309
 | 
    33   return str
 | 
| 
bsw/jbe@1309
 | 
    34 end
 | 
| 
bsw/jbe@1309
 | 
    35 
 | 
| 
bsw/jbe@1309
 | 
    36 local function normalize_name(str)
 | 
| 
bsw/jbe@1309
 | 
    37   local gsub = string.gsub
 | 
| 
bsw/jbe@1309
 | 
    38   str = removeaccent(str)
 | 
| 
bsw/jbe@1309
 | 
    39   str = gsub(str, " ", "")
 | 
| 
bsw/jbe@1309
 | 
    40   str = gsub(str, "-", "")
 | 
| 
bsw/jbe@1309
 | 
    41   str = gsub(str, "'", "")
 | 
| 
bsw/jbe@1309
 | 
    42   str = gsub(str, "\226\128\146", "")
 | 
| 
bsw/jbe@1309
 | 
    43   str = gsub(str, "\226\128\147", "")
 | 
| 
bsw/jbe@1309
 | 
    44   str = gsub(str, "\226\128\148", "")
 | 
| 
bsw/jbe@1309
 | 
    45   if string.find(str, "^[A-Za-z]+$") then
 | 
| 
bsw/jbe@1309
 | 
    46     return string.upper(str)
 | 
| 
bsw/jbe@1309
 | 
    47   else
 | 
| 
bsw/jbe@1309
 | 
    48     return nil
 | 
| 
bsw/jbe@1309
 | 
    49   end
 | 
| 
bsw/jbe@1309
 | 
    50 end
 | 
| 
bsw/jbe@1309
 | 
    51 
 | 
| 
bsw/jbe@1309
 | 
    52 local function remove_consonants(str)
 | 
| 
bsw/jbe@1309
 | 
    53   return (string.gsub(str, "[BCDFGHJKLMNPQRSTVWXYZ]", ""))
 | 
| 
bsw/jbe@1309
 | 
    54 end
 | 
| 
bsw/jbe@1309
 | 
    55 
 | 
| 
bsw/jbe@1309
 | 
    56 local function remove_vowels(str)
 | 
| 
bsw/jbe@1309
 | 
    57   return (string.gsub(str, "[AEIOU]", ""))
 | 
| 
bsw/jbe@1309
 | 
    58 end
 | 
| 
bsw/jbe@1309
 | 
    59 
 | 
| 
bsw/jbe@1309
 | 
    60 local function numberize(str)
 | 
| 
bsw/jbe@1309
 | 
    61   local gsub = string.gsub
 | 
| 
bsw/jbe@1309
 | 
    62   str = gsub(str, "L", "0")
 | 
| 
bsw/jbe@1309
 | 
    63   str = gsub(str, "M", "1")
 | 
| 
bsw/jbe@1309
 | 
    64   str = gsub(str, "N", "2")
 | 
| 
bsw/jbe@1309
 | 
    65   str = gsub(str, "P", "3")
 | 
| 
bsw/jbe@1309
 | 
    66   str = gsub(str, "Q", "4")
 | 
| 
bsw/jbe@1309
 | 
    67   str = gsub(str, "R", "5")
 | 
| 
bsw/jbe@1309
 | 
    68   str = gsub(str, "S", "6")
 | 
| 
bsw/jbe@1309
 | 
    69   str = gsub(str, "T", "7")
 | 
| 
bsw/jbe@1309
 | 
    70   str = gsub(str, "U", "8")
 | 
| 
bsw/jbe@1309
 | 
    71   str = gsub(str, "V", "9")
 | 
| 
bsw/jbe@1309
 | 
    72   return str
 | 
| 
bsw/jbe@1309
 | 
    73 end
 | 
| 
bsw/jbe@1309
 | 
    74 
 | 
| 
bsw/jbe@1309
 | 
    75 return function(code, data)
 | 
| 
bsw/jbe@1309
 | 
    76   local sub = string.sub
 | 
| 
bsw/jbe@1309
 | 
    77   local byte = string.byte
 | 
| 
bsw/jbe@1309
 | 
    78   local byte0 = byte("0")
 | 
| 
bsw/jbe@1309
 | 
    79   local byteA = byte("A")
 | 
| 
bsw/jbe@1309
 | 
    80   local function byteat(str, pos)
 | 
| 
bsw/jbe@1309
 | 
    81     return (byte(sub(str, pos, pos)))
 | 
| 
bsw/jbe@1309
 | 
    82   end
 | 
| 
bsw/jbe@1309
 | 
    83   if #code ~= 16 then
 | 
| 
bsw/jbe@1309
 | 
    84     return false, "Invalid length"
 | 
| 
bsw/jbe@1309
 | 
    85   end
 | 
| 
bsw/jbe@1309
 | 
    86   local sum = 0
 | 
| 
bsw/jbe@1309
 | 
    87   for i = 1, 15, 2 do
 | 
| 
bsw/jbe@1309
 | 
    88     local b = byteat(code, i)
 | 
| 
bsw/jbe@1309
 | 
    89     local b0 = b - byte0
 | 
| 
bsw/jbe@1309
 | 
    90     if b0 >= 0 and b0 <= 9 then
 | 
| 
bsw/jbe@1309
 | 
    91       sum = sum + oddmap[b0]
 | 
| 
bsw/jbe@1309
 | 
    92     else
 | 
| 
bsw/jbe@1309
 | 
    93       local bA = b - byteA
 | 
| 
bsw/jbe@1309
 | 
    94       if bA >= 0 and bA <= 25 then
 | 
| 
bsw/jbe@1309
 | 
    95         sum = sum + oddmap[bA]
 | 
| 
bsw/jbe@1309
 | 
    96       else
 | 
| 
bsw/jbe@1309
 | 
    97         return false, "Invalid character"
 | 
| 
bsw/jbe@1309
 | 
    98       end
 | 
| 
bsw/jbe@1309
 | 
    99     end
 | 
| 
bsw/jbe@1309
 | 
   100   end
 | 
| 
bsw/jbe@1309
 | 
   101   for i = 2, 14, 2 do
 | 
| 
bsw/jbe@1309
 | 
   102     local b = byteat(code, i)
 | 
| 
bsw/jbe@1309
 | 
   103     local b0 = b - byte0
 | 
| 
bsw/jbe@1309
 | 
   104     if b0 >= 0 and b0 <= 9 then
 | 
| 
bsw/jbe@1309
 | 
   105       sum = sum + b0
 | 
| 
bsw/jbe@1309
 | 
   106     else
 | 
| 
bsw/jbe@1309
 | 
   107       local bA = b - byteA
 | 
| 
bsw/jbe@1309
 | 
   108       if bA >= 0 and bA <= 25 then
 | 
| 
bsw/jbe@1309
 | 
   109         sum = sum + bA
 | 
| 
bsw/jbe@1309
 | 
   110       else
 | 
| 
bsw/jbe@1309
 | 
   111         return false, "Invalid character"
 | 
| 
bsw/jbe@1309
 | 
   112       end
 | 
| 
bsw/jbe@1309
 | 
   113     end
 | 
| 
bsw/jbe@1309
 | 
   114   end
 | 
| 
bsw/jbe@1309
 | 
   115   local check = byteat(code, 16)
 | 
| 
bsw/jbe@1309
 | 
   116   local checkA = check - byteA
 | 
| 
bsw/jbe@1309
 | 
   117   if checkA >= 0 and checkA <= 25 then
 | 
| 
bsw/jbe@1309
 | 
   118     if checkA ~= sum % 26 then
 | 
| 
bsw/jbe@1309
 | 
   119       return false, "Invalid checksum"
 | 
| 
bsw/jbe@1309
 | 
   120     end
 | 
| 
bsw/jbe@1309
 | 
   121   else
 | 
| 
bsw/jbe@1309
 | 
   122     local check0 = check - byte0
 | 
| 
bsw/jbe@1309
 | 
   123     if check0 >= 0 and check0 <= 9 then
 | 
| 
bsw/jbe@1309
 | 
   124       return false, "Checksum must not be numeric"
 | 
| 
bsw/jbe@1309
 | 
   125     else
 | 
| 
bsw/jbe@1309
 | 
   126       return false, "Invalid character"
 | 
| 
bsw/jbe@1309
 | 
   127     end
 | 
| 
bsw/jbe@1309
 | 
   128   end
 | 
| 
bsw/jbe@1309
 | 
   129   if data then
 | 
| 
bsw/jbe@1309
 | 
   130     if data.last_name then
 | 
| 
bsw/jbe@1309
 | 
   131       local name = normalize_name(data.last_name)
 | 
| 
bsw/jbe@1309
 | 
   132       if not name then
 | 
| 
bsw/jbe@1309
 | 
   133         return false, "Invalid last name"
 | 
| 
bsw/jbe@1309
 | 
   134       end
 | 
| 
bsw/jbe@1309
 | 
   135       local consonants = remove_vowels(name)
 | 
| 
bsw/jbe@1309
 | 
   136       local short = sub(consonants, 1, 3)
 | 
| 
bsw/jbe@1309
 | 
   137       if #short < 3 then
 | 
| 
bsw/jbe@1309
 | 
   138         local vowels = remove_consonants(name)
 | 
| 
bsw/jbe@1309
 | 
   139         short = short .. sub(vowels, 1, 3 - #short)
 | 
| 
bsw/jbe@1309
 | 
   140         while #short < 3 do
 | 
| 
bsw/jbe@1309
 | 
   141           short = short .. "X"
 | 
| 
bsw/jbe@1309
 | 
   142         end
 | 
| 
bsw/jbe@1309
 | 
   143       end
 | 
| 
bsw/jbe@1309
 | 
   144       if short ~= sub(code, 1, 3) then
 | 
| 
bsw/jbe@1309
 | 
   145         return false, "Last name not matching"
 | 
| 
bsw/jbe@1309
 | 
   146       end
 | 
| 
bsw/jbe@1309
 | 
   147     end
 | 
| 
bsw/jbe@1309
 | 
   148     if data.first_name then
 | 
| 
bsw/jbe@1309
 | 
   149       local name = normalize_name(data.first_name)
 | 
| 
bsw/jbe@1309
 | 
   150       if not name then
 | 
| 
bsw/jbe@1309
 | 
   151         return false, "Invalid first name"
 | 
| 
bsw/jbe@1309
 | 
   152       end
 | 
| 
bsw/jbe@1309
 | 
   153       local consonants = remove_vowels(name)
 | 
| 
bsw/jbe@1309
 | 
   154       local short
 | 
| 
bsw/jbe@1309
 | 
   155       if #consonants >= 4 then
 | 
| 
bsw/jbe@1309
 | 
   156         short = sub(consonants, 1, 1) .. sub(consonants, 3, 4)
 | 
| 
bsw/jbe@1309
 | 
   157       else
 | 
| 
bsw/jbe@1309
 | 
   158         short = consonants
 | 
| 
bsw/jbe@1309
 | 
   159         if #short < 3 then
 | 
| 
bsw/jbe@1309
 | 
   160           local vowels = remove_consonants(name)
 | 
| 
bsw/jbe@1309
 | 
   161           short = short .. sub(vowels, 1, 3 - #short)
 | 
| 
bsw/jbe@1309
 | 
   162           while #short < 3 do
 | 
| 
bsw/jbe@1309
 | 
   163             short = short .. "X"
 | 
| 
bsw/jbe@1309
 | 
   164           end
 | 
| 
bsw/jbe@1309
 | 
   165         end
 | 
| 
bsw/jbe@1309
 | 
   166       end
 | 
| 
bsw/jbe@1309
 | 
   167       if short ~= sub(code, 4, 6) then
 | 
| 
bsw/jbe@1309
 | 
   168         return false, "First name not matching"
 | 
| 
bsw/jbe@1309
 | 
   169       end
 | 
| 
bsw/jbe@1309
 | 
   170     end
 | 
| 
bsw/jbe@1309
 | 
   171     if data.year then
 | 
| 
bsw/jbe@1309
 | 
   172       local year = tostring(data.year % 100)
 | 
| 
bsw/jbe@1309
 | 
   173       if #year < 2 then
 | 
| 
bsw/jbe@1309
 | 
   174         year = "0" .. year
 | 
| 
bsw/jbe@1309
 | 
   175       end
 | 
| 
bsw/jbe@1309
 | 
   176       if year ~= numberize(sub(code, 7, 8)) then
 | 
| 
bsw/jbe@1309
 | 
   177         return false, "Year of birth not matching"
 | 
| 
bsw/jbe@1309
 | 
   178       end
 | 
| 
bsw/jbe@1309
 | 
   179     end
 | 
| 
bsw/jbe@1309
 | 
   180     if data.month then
 | 
| 
bsw/jbe@1309
 | 
   181       local monthchar = monthtable[data.month]
 | 
| 
bsw/jbe@1309
 | 
   182       if monthchar ~= sub(code, 9, 9) then
 | 
| 
bsw/jbe@1309
 | 
   183         return false, "Month of birth not matching"
 | 
| 
bsw/jbe@1309
 | 
   184       end
 | 
| 
bsw/jbe@1309
 | 
   185     end
 | 
| 
bsw/jbe@1309
 | 
   186     if data.day then
 | 
| 
bsw/jbe@1309
 | 
   187       local day = tostring(data.day)
 | 
| 
bsw/jbe@1309
 | 
   188       if #day < 2 then
 | 
| 
bsw/jbe@1309
 | 
   189         day = "0" .. day
 | 
| 
bsw/jbe@1309
 | 
   190       end
 | 
| 
bsw/jbe@1309
 | 
   191       local daycode = numberize(sub(code, 10, 11))
 | 
| 
bsw/jbe@1309
 | 
   192       if day ~= daycode and tostring(day + 40) ~= daycode then
 | 
| 
bsw/jbe@1309
 | 
   193         return false, "Day of birth not matching"
 | 
| 
bsw/jbe@1309
 | 
   194       end
 | 
| 
bsw/jbe@1309
 | 
   195     end
 | 
| 
bsw/jbe@1309
 | 
   196   end
 | 
| 
bsw/jbe@1309
 | 
   197   return true
 | 
| 
bsw/jbe@1309
 | 
   198 end
 |