fix #62, properly handle ansi encoded names
This commit is contained in:
parent
91e5da9eab
commit
d4be18cb81
|
@ -29,7 +29,7 @@ const val DEFAULT_EVENT_TYPE = CommonDataKinds.Event.TYPE_BIRTHDAY
|
||||||
// export/import
|
// export/import
|
||||||
const val BEGIN_VCARD = "BEGIN:VCARD"
|
const val BEGIN_VCARD = "BEGIN:VCARD"
|
||||||
const val END_VCARD = "END:VCARD"
|
const val END_VCARD = "END:VCARD"
|
||||||
const val N = "N:"
|
const val N = "N"
|
||||||
const val TEL = "TEL"
|
const val TEL = "TEL"
|
||||||
const val BDAY = "BDAY:"
|
const val BDAY = "BDAY:"
|
||||||
const val ANNIVERSARY = "ANNIVERSARY:"
|
const val ANNIVERSARY = "ANNIVERSARY:"
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
package com.simplemobiletools.contacts.helpers
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
|
|
||||||
|
// https://alvinalexander.com/java/jwarehouse/android/core/java/com/google/android/mms/pdu/QuotedPrintable.java.shtml
|
||||||
|
object QuotedPrintable {
|
||||||
|
private const val ESCAPE_CHAR: Byte = '='.toByte()
|
||||||
|
fun decode(value: String?): String {
|
||||||
|
val bytes = value?.toByteArray()
|
||||||
|
if (bytes == null || bytes.isEmpty()) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
val buffer = ByteArrayOutputStream()
|
||||||
|
var i = 0
|
||||||
|
while (i < bytes.size) {
|
||||||
|
val b = bytes[i].toInt()
|
||||||
|
if (b == ESCAPE_CHAR.toInt()) {
|
||||||
|
try {
|
||||||
|
if ('\r' == bytes[i + 1].toChar() && '\n' == bytes[i + 2].toChar()) {
|
||||||
|
i += 2
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
val u = Character.digit(bytes[++i].toChar(), 16)
|
||||||
|
val l = Character.digit(bytes[++i].toChar(), 16)
|
||||||
|
if (u == -1 || l == -1) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.write(((u shl 4) + l).toChar().toInt())
|
||||||
|
} catch (e: ArrayIndexOutOfBoundsException) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
buffer.write(b)
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return String(buffer.toByteArray())
|
||||||
|
}
|
||||||
|
}
|
|
@ -36,7 +36,7 @@ class VcfExporter {
|
||||||
for (contact in contacts) {
|
for (contact in contacts) {
|
||||||
out.writeLn(BEGIN_VCARD)
|
out.writeLn(BEGIN_VCARD)
|
||||||
out.writeLn(VERSION_2_1)
|
out.writeLn(VERSION_2_1)
|
||||||
out.writeLn("$N${contact.surname};${contact.firstName};${contact.middleName};;")
|
out.writeLn("$N:${contact.surname};${contact.firstName};${contact.middleName};;")
|
||||||
|
|
||||||
contact.phoneNumbers.forEach {
|
contact.phoneNumbers.forEach {
|
||||||
out.writeLn("$TEL;${getPhoneNumberLabel(it.type)}:${it.value}")
|
out.writeLn("$TEL;${getPhoneNumberLabel(it.type)}:${it.value}")
|
||||||
|
|
|
@ -82,11 +82,13 @@ class VcfImporter(val activity: SimpleActivity) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseNames(names: String) {
|
private fun parseNames(names: String) {
|
||||||
val nameParts = names.split(";")
|
val parts = names.split(":")
|
||||||
curSurname = nameParts[0]
|
val isANSI = parts.first().toUpperCase().contains("QUOTED-PRINTABLE")
|
||||||
curFirstName = nameParts[1]
|
val nameParts = parts[1].split(";")
|
||||||
|
curSurname = if (isANSI) QuotedPrintable.decode(nameParts[0]) else nameParts[0]
|
||||||
|
curFirstName = if (isANSI) QuotedPrintable.decode(nameParts[1]) else nameParts[1]
|
||||||
if (nameParts.size > 2) {
|
if (nameParts.size > 2) {
|
||||||
curMiddleName = nameParts[2]
|
curMiddleName = if (isANSI) QuotedPrintable.decode(nameParts[2]) else nameParts[2]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue