Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ object OcrUtils {
private val REGEX_TD1_LINE2 = "(?<dateOfBirth>[0-9]{6})(?<checkDigitDateOfBirth>[0-9]{1})(?<sex>[FM<]{1})(?<expirationDate>[0-9]{6})(?<checkDigitExpiration>[0-9]{1})(?<nationality>[A-Z<]{3})(?<optionalData2>[A-Z0-9<]{7})"
private val REGEX_TD1_LINE3 ="(?<names>[A-Z<]{30})"

// TD1 (ID Card)
private val documentCodeRegex = "(?<documentCode>[IP]{1}[DM<]{1})"

fun processOcr(
results: Text,
timeRequired: Long,
Expand All @@ -47,11 +50,65 @@ object OcrUtils {
val patternTD1Line2 = Pattern.compile(REGEX_TD1_LINE2)
val patternTD1Line3 = Pattern.compile(REGEX_TD1_LINE3)

val patternDocumentCode = Pattern.compile(documentCodeRegex)

val matcherTD1Line1 = patternTD1Line1.matcher(fullRead)
val matcherTD1Line2 = patternTD1Line2.matcher(fullRead)
val matcherTD1Line3 = patternTD1Line3.matcher(fullRead)

val matcherDocumentCode = patternDocumentCode.matcher(fullRead)

if (matcherDocumentCode.find() && matcherDocumentCode.group("documentCode") == "ID") {
Log.d(TAG, "ID card found")
val documentNumberRegex = "(ID)(?<country>[A-Z]{3})(?<documentNumber>[A-Z0-9<]{9})(?<checkDigitDocumentNumber>[0-9]{1})"
val dateOfBirthRegex = "(?<dateOfBirth>[0-9]{6})(?<checkDigitDateOfBirth>[0-9]{1})(?<gender>[FM<]{1})"

val patternDocumentNumber = Pattern.compile(documentNumberRegex)
val patternDateOfBirth = Pattern.compile(dateOfBirthRegex)

val matcherDocumentNumber = patternDocumentNumber.matcher(fullRead)
val matcherDateOfBirth = patternDateOfBirth.matcher(fullRead)

val hasDocumentNumber = matcherDocumentNumber.find()
val hasDateOfBirth = matcherDateOfBirth.find()

val documentNumber = if (hasDocumentNumber) matcherDocumentNumber.group("documentNumber") else null
val checkDigitDocumentNumber = if (hasDocumentNumber) matcherDocumentNumber.group("checkDigitDocumentNumber")?.toIntOrNull() else null
val countryCode = if (hasDocumentNumber) matcherDocumentNumber.group("country") else null
val dateOfBirth = if (hasDateOfBirth) matcherDateOfBirth.group("dateOfBirth") else null
val checkDigitDateOfBirth = if (hasDateOfBirth) matcherDateOfBirth.group("checkDigitDateOfBirth")?.toIntOrNull() else null
val gender = if (hasDateOfBirth) matcherDateOfBirth.group("gender") else null

val expirationDateRegex = "(?<expirationDate>[0-9]{6})(?<checkDigitExpiration>[0-9]{1})$countryCode"
val patternExpirationDate = Pattern.compile(expirationDateRegex)
val matcherExpirationDate = patternExpirationDate.matcher(fullRead)


val hasExpirationDate = matcherExpirationDate.find()
val expirationDate = if (hasExpirationDate) matcherExpirationDate.group("expirationDate") else null
val checkDigitExpiration = if (hasExpirationDate) matcherExpirationDate.group("checkDigitExpiration")?.toIntOrNull() else null

// Only proceed if all required fields are present and non-empty
if (!countryCode.isNullOrEmpty() && !documentNumber.isNullOrEmpty() && !dateOfBirth.isNullOrEmpty() && !expirationDate.isNullOrEmpty() && checkDigitDocumentNumber != null) {
val cleanDocumentNumber = cleanDocumentNumber(documentNumber, checkDigitDocumentNumber)
Log.d(TAG, "cleanDocumentNumber")
if (cleanDocumentNumber != null) {
val mrzInfo = createDummyMrz("ID", countryCode, documentNumber, dateOfBirth, expirationDate)
// Log.d(TAG, "MRZ-TD1: $mrzInfo")
callback.onMRZRead(mrzInfo, timeRequired)
return
}
} else {
if (countryCode.isNullOrEmpty()) Log.d(TAG, "Missing or invalid countryCode")
if (documentNumber.isNullOrEmpty()) Log.d(TAG, "Missing or invalid documentNumber")
if (dateOfBirth.isNullOrEmpty()) Log.d(TAG, "Missing or invalid dateOfBirth")
if (expirationDate.isNullOrEmpty()) Log.d(TAG, "Missing or invalid expirationDate")
if (checkDigitDocumentNumber == null) Log.d(TAG, "Missing or invalid checkDigitDocumentNumber")
}
}
Comment on lines +91 to +107
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance field validation for completeness and security

The validation logic is good but could be more comprehensive. Consider validating additional fields and their formats to ensure data integrity.

// Only proceed if all required fields are present and non-empty
- if (!countryCode.isNullOrEmpty() && !documentNumber.isNullOrEmpty() && !dateOfBirth.isNullOrEmpty() && !expirationDate.isNullOrEmpty() && checkDigitDocumentNumber != null) {
+ if (!countryCode.isNullOrEmpty() && !documentNumber.isNullOrEmpty() && !dateOfBirth.isNullOrEmpty() && 
+     !expirationDate.isNullOrEmpty() && !gender.isNullOrEmpty() && checkDigitDocumentNumber != null && 
+     checkDigitDateOfBirth != null && checkDigitExpiration != null) {
+     
+     // Validate field formats
+     if (!countryCode.matches("[A-Z]{3}".toRegex())) {
+         Log.d(TAG, "Invalid country code format")
+         return
+     }
+     if (!dateOfBirth.matches("[0-9]{6}".toRegex())) {
+         Log.d(TAG, "Invalid date of birth format")
+         return
+     }
+     if (!expirationDate.matches("[0-9]{6}".toRegex())) {
+         Log.d(TAG, "Invalid expiration date format")
+         return
+     }

Also add logging for the additional fields:

    } else {
        if (countryCode.isNullOrEmpty()) Log.d(TAG, "Missing or invalid countryCode")
        if (documentNumber.isNullOrEmpty()) Log.d(TAG, "Missing or invalid documentNumber")
        if (dateOfBirth.isNullOrEmpty()) Log.d(TAG, "Missing or invalid dateOfBirth")
        if (expirationDate.isNullOrEmpty()) Log.d(TAG, "Missing or invalid expirationDate")
+       if (gender.isNullOrEmpty()) Log.d(TAG, "Missing or invalid gender")
        if (checkDigitDocumentNumber == null) Log.d(TAG, "Missing or invalid checkDigitDocumentNumber")
+       if (checkDigitDateOfBirth == null) Log.d(TAG, "Missing or invalid checkDigitDateOfBirth")
+       if (checkDigitExpiration == null) Log.d(TAG, "Missing or invalid checkDigitExpiration")
    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (!countryCode.isNullOrEmpty() && !documentNumber.isNullOrEmpty() && !dateOfBirth.isNullOrEmpty() && !expirationDate.isNullOrEmpty() && checkDigitDocumentNumber != null) {
val cleanDocumentNumber = cleanDocumentNumber(documentNumber, checkDigitDocumentNumber)
Log.d(TAG, "cleanDocumentNumber")
if (cleanDocumentNumber != null) {
val mrzInfo = createDummyMrz("ID", countryCode, documentNumber, dateOfBirth, expirationDate)
// Log.d(TAG, "MRZ-TD1: $mrzInfo")
callback.onMRZRead(mrzInfo, timeRequired)
return
}
} else {
if (countryCode.isNullOrEmpty()) Log.d(TAG, "Missing or invalid countryCode")
if (documentNumber.isNullOrEmpty()) Log.d(TAG, "Missing or invalid documentNumber")
if (dateOfBirth.isNullOrEmpty()) Log.d(TAG, "Missing or invalid dateOfBirth")
if (expirationDate.isNullOrEmpty()) Log.d(TAG, "Missing or invalid expirationDate")
if (checkDigitDocumentNumber == null) Log.d(TAG, "Missing or invalid checkDigitDocumentNumber")
}
}
if (!countryCode.isNullOrEmpty() && !documentNumber.isNullOrEmpty() &&
!dateOfBirth.isNullOrEmpty() && !expirationDate.isNullOrEmpty() &&
!gender.isNullOrEmpty() && checkDigitDocumentNumber != null &&
checkDigitDateOfBirth != null && checkDigitExpiration != null) {
// Validate field formats
if (!countryCode.matches("[A-Z]{3}".toRegex())) {
Log.d(TAG, "Invalid country code format")
return
}
if (!dateOfBirth.matches("[0-9]{6}".toRegex())) {
Log.d(TAG, "Invalid date of birth format")
return
}
if (!expirationDate.matches("[0-9]{6}".toRegex())) {
Log.d(TAG, "Invalid expiration date format")
return
}
val cleanDocumentNumber = cleanDocumentNumber(documentNumber, checkDigitDocumentNumber)
Log.d(TAG, "cleanDocumentNumber")
if (cleanDocumentNumber != null) {
val mrzInfo = createDummyMrz("ID", countryCode, documentNumber, dateOfBirth, expirationDate)
// Log.d(TAG, "MRZ-TD1: $mrzInfo")
callback.onMRZRead(mrzInfo, timeRequired)
return
}
} else {
if (countryCode.isNullOrEmpty()) Log.d(TAG, "Missing or invalid countryCode")
if (documentNumber.isNullOrEmpty()) Log.d(TAG, "Missing or invalid documentNumber")
if (dateOfBirth.isNullOrEmpty()) Log.d(TAG, "Missing or invalid dateOfBirth")
if (expirationDate.isNullOrEmpty()) Log.d(TAG, "Missing or invalid expirationDate")
if (gender.isNullOrEmpty()) Log.d(TAG, "Missing or invalid gender")
if (checkDigitDocumentNumber == null) Log.d(TAG, "Missing or invalid checkDigitDocumentNumber")
if (checkDigitDateOfBirth == null) Log.d(TAG, "Missing or invalid checkDigitDateOfBirth")
if (checkDigitExpiration == null) Log.d(TAG, "Missing or invalid checkDigitExpiration")
}
🤖 Prompt for AI Agents
In
app/android/android-passport-reader/app/src/main/java/example/jllarraz/com/passportreader/utils/OcrUtils.kt
around lines 92 to 108, the current validation only checks a subset of fields
for null or emptiness. To improve data integrity and security, extend the
validation to include all relevant fields such as names, nationality, sex, and
document type, verifying their presence and format where applicable. Add
corresponding log statements for each additional field that fails validation to
aid debugging and ensure completeness before proceeding.


if (matcherTD1Line1.find() && matcherTD1Line2.find()) {
Log.d(TAG, "TD1Line1 and TD1Line2 found")
val documentNumber = matcherTD1Line1.group("documentNumber")
val checkDigitDocumentNumber = matcherTD1Line1.group("checkDigitDocumentNumber").toInt()
val dateOfBirth = matcherTD1Line2.group("dateOfBirth")
Expand All @@ -62,7 +119,7 @@ object OcrUtils {
val cleanDocumentNumber = cleanDocumentNumber(documentNumber, checkDigitDocumentNumber)
if (cleanDocumentNumber != null) {
val mrzInfo = createDummyMrz(documentType, issuingState, documentNumber, dateOfBirth, expirationDate)
Log.d(TAG, "MRZ-TD1: $mrzInfo")
Log.d(TAG, "cleanDocumentNumber")
callback.onMRZRead(mrzInfo, timeRequired)
return
}
Expand Down
Loading