package com.documentaccept.rn.mrzscanner /** * Port of the iOS StringUtils checkMrz logic — validates / assembles MRZ lines. */ object MRZUtils { private val ALLOWED = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789<".toSet() // TD-1 (ID cards, 3 lines × 30 chars) private val TD1_LINE1 = Regex("(I|C|A).[A-Z0<]{3}[A-Z0-9]{1,9} st st.length < targetLength -> st + "<".repeat(targetLength - st.length) else -> st.take(targetLength) } } @Synchronized fun checkMrz(candidate: String): String? { val clean = candidate .uppercase() .replace(" ", "<") .filter { it in ALLOWED } // TD-1 patterns if (TD1_LINE1.containsMatchIn(clean) && clean.length in 25..36) { captureFirst = normalizedMRZLine(clean, 30) } if (TD1_LINE2.containsMatchIn(clean) && clean.length in 25..36) { captureSecond = normalizedMRZLine(clean, 30) } if (TD1_LINE3.containsMatchIn(clean) && clean.length in 25..36) { captureThird = normalizedMRZLine(clean, 30) } // TD-3 patterns if (TD3_LINE1.containsMatchIn(clean) && clean.length in 38..50) { captureFirst = normalizedMRZLine(clean, 44) } if (TD3_LINE2.containsMatchIn(clean) && clean.length in 38..50) { captureSecond = normalizedMRZLine(clean, 44) } // Assemble TD-1 if (captureFirst.length == 30 && captureSecond.length == 30 && captureThird.length == 30) { val assembled = "${stripped(captureFirst)}\n${stripped(captureSecond)}\n${stripped(captureThird)}" .replace(" ", "<") return assembled } // Assemble TD-3 if (captureFirst.length == 44 && captureSecond.length == 44) { val assembled = "${stripped(captureFirst)}\n${stripped(captureSecond)}" .replace(" ", "<") return assembled } return null } @Synchronized fun resetCaptures() { captureFirst = "" captureSecond = "" captureThird = "" } }