summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJay Shrauner <shrauner@google.com>2014-07-22 12:36:21 -0700
committerJay Shrauner <shrauner@google.com>2014-07-23 14:21:39 -0700
commit210ebaab315e389ffc66278e28ecd6230e412b5f (patch)
tree1f1c4d9d5fcdf0ca48cf31498eb2ce0ef952535a
parent4950d922815e16a0724e2509a6d04ccef8bd810b (diff)
downloadvcard-210ebaab315e389ffc66278e28ecd6230e412b5f.tar.gz
Fix import of iOS vcardsandroid-wear-5.1.1_r1android-wear-5.1.0_r1android-wear-5.0.0_r1android-m-preview-2android-m-preview-1android-m-previewandroid-cts-5.1_r9android-cts-5.1_r8android-cts-5.1_r7android-cts-5.1_r6android-cts-5.1_r5android-cts-5.1_r4android-cts-5.1_r3android-cts-5.1_r28android-cts-5.1_r27android-cts-5.1_r26android-cts-5.1_r25android-cts-5.1_r24android-cts-5.1_r23android-cts-5.1_r22android-cts-5.1_r21android-cts-5.1_r20android-cts-5.1_r2android-cts-5.1_r19android-cts-5.1_r18android-cts-5.1_r17android-cts-5.1_r16android-cts-5.1_r15android-cts-5.1_r14android-cts-5.1_r13android-cts-5.1_r10android-cts-5.1_r1android-cts-5.0_r9android-cts-5.0_r8android-cts-5.0_r7android-cts-5.0_r6android-cts-5.0_r5android-cts-5.0_r4android-cts-5.0_r3android-5.1.1_r9android-5.1.1_r8android-5.1.1_r7android-5.1.1_r6android-5.1.1_r5android-5.1.1_r4android-5.1.1_r38android-5.1.1_r37android-5.1.1_r36android-5.1.1_r35android-5.1.1_r34android-5.1.1_r33android-5.1.1_r30android-5.1.1_r3android-5.1.1_r29android-5.1.1_r28android-5.1.1_r26android-5.1.1_r25android-5.1.1_r24android-5.1.1_r23android-5.1.1_r22android-5.1.1_r20android-5.1.1_r2android-5.1.1_r19android-5.1.1_r18android-5.1.1_r17android-5.1.1_r16android-5.1.1_r15android-5.1.1_r14android-5.1.1_r13android-5.1.1_r12android-5.1.1_r10android-5.1.1_r1android-5.1.0_r5android-5.1.0_r4android-5.1.0_r3android-5.1.0_r1android-5.0.2_r3android-5.0.2_r1android-5.0.1_r1android-5.0.0_r7android-5.0.0_r6android-5.0.0_r5.1android-5.0.0_r5android-5.0.0_r4android-5.0.0_r3android-5.0.0_r2android-5.0.0_r1master-soonglollipop-wear-releaselollipop-releaselollipop-mr1-wfc-releaselollipop-mr1-releaselollipop-mr1-fi-releaselollipop-mr1-devlollipop-mr1-cts-releaselollipop-devlollipop-cts-release
Fix handling of multiline data blocks in v3.0 vcards with \r\r\n line terminators. Bug:16433675 Change-Id: I77c7c94fa1b13e18e53459e94c3c73ad53b7d8e2
-rw-r--r--java/com/android/vcard/VCardParserImpl_V21.java7
-rw-r--r--java/com/android/vcard/VCardParserImpl_V30.java101
-rw-r--r--tests/res/raw/v30_ios_613_multiline.vcf104
-rw-r--r--tests/src/com/android/vcard/tests/VCardParserTests.java35
4 files changed, 175 insertions, 72 deletions
diff --git a/java/com/android/vcard/VCardParserImpl_V21.java b/java/com/android/vcard/VCardParserImpl_V21.java
index aaf442f..386d626 100644
--- a/java/com/android/vcard/VCardParserImpl_V21.java
+++ b/java/com/android/vcard/VCardParserImpl_V21.java
@@ -450,7 +450,7 @@ import java.util.Set;
} else if (paramName.equals("VALUE")) {
handleValue(propertyData, paramValue);
} else if (paramName.equals("ENCODING")) {
- handleEncoding(propertyData, paramValue);
+ handleEncoding(propertyData, paramValue.toUpperCase());
} else if (paramName.equals("CHARSET")) {
handleCharset(propertyData, paramValue);
} else if (paramName.equals("LANGUAGE")) {
@@ -862,7 +862,10 @@ import java.util.Set;
if (line.length() == 0) {
break;
}
- builder.append(line);
+ // Trim off any extraneous whitespace to handle 2.1 implementations
+ // that use 3.0 style line continuations. This is safe because space
+ // isn't a Base64 encoding value.
+ builder.append(line.trim());
}
return builder.toString();
diff --git a/java/com/android/vcard/VCardParserImpl_V30.java b/java/com/android/vcard/VCardParserImpl_V30.java
index eb63010..357383b 100644
--- a/java/com/android/vcard/VCardParserImpl_V30.java
+++ b/java/com/android/vcard/VCardParserImpl_V30.java
@@ -78,64 +78,41 @@ import java.util.Set;
protected String getNonEmptyLine() throws IOException, VCardException {
String line;
StringBuilder builder = null;
- while (true) {
- line = mReader.readLine();
- if (line == null) {
- if (builder != null) {
- return builder.toString();
- } else if (mPreviousLine != null) {
- String ret = mPreviousLine;
- mPreviousLine = null;
- return ret;
- }
- throw new VCardException("Reached end of buffer.");
- } else if (line.length() == 0) {
- if (builder != null) {
- return builder.toString();
- } else if (mPreviousLine != null) {
- String ret = mPreviousLine;
- mPreviousLine = null;
- return ret;
- }
+ while ((line = mReader.readLine()) != null) {
+ // Skip empty lines in order to accomodate implementations that
+ // send line termination variations such as \r\r\n.
+ if (line.length() == 0) {
+ continue;
} else if (line.charAt(0) == ' ' || line.charAt(0) == '\t') {
- if (builder != null) {
- // See Section 5.8.1 of RFC 2425 (MIME-DIR document).
- // Following is the excerpts from it.
- //
- // DESCRIPTION:This is a long description that exists on a long line.
- //
- // Can be represented as:
- //
- // DESCRIPTION:This is a long description
- // that exists on a long line.
- //
- // It could also be represented as:
- //
- // DESCRIPTION:This is a long descrip
- // tion that exists o
- // n a long line.
- builder.append(line.substring(1));
- } else if (mPreviousLine != null) {
+ // RFC 2425 describes line continuation as \r\n followed by
+ // a single ' ' or '\t' whitespace character.
+ if (builder == null) {
builder = new StringBuilder();
+ }
+ if (mPreviousLine != null) {
builder.append(mPreviousLine);
mPreviousLine = null;
- builder.append(line.substring(1));
- } else {
- throw new VCardException("Space exists at the beginning of the line");
}
+ builder.append(line.substring(1));
} else {
- if (mPreviousLine == null) {
- mPreviousLine = line;
- if (builder != null) {
- return builder.toString();
- }
- } else {
- String ret = mPreviousLine;
- mPreviousLine = line;
- return ret;
+ if (builder != null || mPreviousLine != null) {
+ break;
}
+ mPreviousLine = line;
}
}
+
+ String ret = null;
+ if (builder != null) {
+ ret = builder.toString();
+ } else if (mPreviousLine != null) {
+ ret = mPreviousLine;
+ }
+ mPreviousLine = line;
+ if (ret == null) {
+ throw new VCardException("Reached end of buffer.");
+ }
+ return ret;
}
/*
@@ -313,30 +290,16 @@ import java.util.Set;
}
/**
- * vCard 3.0 does not require two CRLF at the last of BASE64 data.
- * It only requires that data should be MIME-encoded.
+ * This is only called from handlePropertyValue(), which has already
+ * read the first line of this property. With v3.0, the getNonEmptyLine()
+ * routine has already concatenated all following continuation lines.
+ * The routine is implemented in the V21 parser to concatenate v2.1 style
+ * data blocks, but is unnecessary here.
*/
@Override
protected String getBase64(final String firstString)
throws IOException, VCardException {
- final StringBuilder builder = new StringBuilder();
- builder.append(firstString);
-
- while (true) {
- final String line = getLine();
- if (line == null) {
- throw new VCardException("File ended during parsing BASE64 binary");
- }
- if (line.length() == 0) {
- break;
- } else if (!line.startsWith(" ") && !line.startsWith("\t")) {
- mPreviousLine = line;
- break;
- }
- builder.append(line);
- }
-
- return builder.toString();
+ return firstString;
}
/**
diff --git a/tests/res/raw/v30_ios_613_multiline.vcf b/tests/res/raw/v30_ios_613_multiline.vcf
new file mode 100644
index 0000000..4e737bd
--- /dev/null
+++ b/tests/res/raw/v30_ios_613_multiline.vcf
@@ -0,0 +1,104 @@
+BEGIN:VCARD
+VERSION:3.0
+N:Smith;Bob;;;
+FN:Bob Smith
+ORG:Smith Auto Repair;
+item1.EMAIL;type=INTERNET;type=pref:bob@smithauto.com
+TEL;type=CELL;type=VOICE;type=pref:(650) 555-1212
+item2.URL;type=pref:www.smithauto.com
+item2.X-ABLabel:_$!<HomePage>!$_
+PHOTO;ENCODING=b;TYPE=JPEG:/9j/4AAQSkZJRgABAQAAAQABAAD/4gxYSUNDX1BST0ZJTEUA
+ AQEAAAxITGlubwIQAABtbnRyUkdCIFhZWiAHzgACAAkABgAxAABhY3NwTVNGVAAAAABJRUMgc1
+ JHQgAAAAAAAAAAAAAAAAAA9tYAAQAAAADTLUhQICAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAABFjcHJ0AAABUAAAADNkZXNjAAABhAAAAGx3dHB0AAAB8A
+ AAABRia3B0AAACBAAAABRyWFlaAAACGAAAABRnWFlaAAACLAAAABRiWFlaAAACQAAAABRkbW5k
+ AAACVAAAAHBkbWRkAAACxAAAAIh2dWVkAAADTAAAAIZ2aWV3AAAD1AAAACRsdW1pAAAD+AAAAB
+ RtZWFzAAAEDAAAACR0ZWNoAAAEMAAAAAxyVFJDAAAEPAAACAxnVFJDAAAEPAAACAxiVFJDAAAE
+ PAAACAx0ZXh0AAAAAENvcHlyaWdodCAoYykgMTk5OCBIZXdsZXR0LVBhY2thcmQgQ29tcGFueQ
+ AAZGVzYwAAAAAAAAASc1JHQiBJRUM2MTk2Ni0yLjEAAAAAAAAAAAAAABJzUkdCIElFQzYxOTY2
+ LTIuMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWF
+ laIAAAAAAAAPNRAAEAAAABFsxYWVogAAAAAAAAAAAAAAAAAAAAAFhZWiAAAAAAAABvogAAOPUA
+ AAOQWFlaIAAAAAAAAGKZAAC3hQAAGNpYWVogAAAAAAAAJKAAAA+EAAC2z2Rlc2MAAAAAAAAAFk
+ lFQyBodHRwOi8vd3d3LmllYy5jaAAAAAAAAAAAAAAAFklFQyBodHRwOi8vd3d3LmllYy5jaAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkZXNjAAAAAAAAAC
+ 5JRUMgNjE5NjYtMi4xIERlZmF1bHQgUkdCIGNvbG91ciBzcGFjZSAtIHNSR0IAAAAAAAAAAAAA
+ AC5JRUMgNjE5NjYtMi4xIERlZmF1bHQgUkdCIGNvbG91ciBzcGFjZSAtIHNSR0IAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAZGVzYwAAAAAAAAAsUmVmZXJlbmNlIFZpZXdpbmcgQ29uZGl0aW9uIGlu
+ IElFQzYxOTY2LTIuMQAAAAAAAAAAAAAALFJlZmVyZW5jZSBWaWV3aW5nIENvbmRpdGlvbiBpbi
+ BJRUM2MTk2Ni0yLjEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHZpZXcAAAAAABOk/gAUXy4A
+ EM8UAAPtzAAEEwsAA1yeAAAAAVhZWiAAAAAAAEwJVgBQAAAAVx/nbWVhcwAAAAAAAAABAAAAAA
+ AAAAAAAAAAAAAAAAAAAo8AAAACc2lnIAAAAABDUlQgY3VydgAAAAAAAAQAAAAABQAKAA8AFAAZ
+ AB4AIwAoAC0AMgA3ADsAQABFAEoATwBUAFkAXgBjAGgAbQByAHcAfACBAIYAiwCQAJUAmgCfAK
+ QAqQCuALIAtwC8AMEAxgDLANAA1QDbAOAA5QDrAPAA9gD7AQEBBwENARMBGQEfASUBKwEyATgB
+ PgFFAUwBUgFZAWABZwFuAXUBfAGDAYsBkgGaAaEBqQGxAbkBwQHJAdEB2QHhAekB8gH6AgMCDA
+ IUAh0CJgIvAjgCQQJLAlQCXQJnAnECegKEAo4CmAKiAqwCtgLBAssC1QLgAusC9QMAAwsDFgMh
+ Ay0DOANDA08DWgNmA3IDfgOKA5YDogOuA7oDxwPTA+AD7AP5BAYEEwQgBC0EOwRIBFUEYwRxBH
+ 4EjASaBKgEtgTEBNME4QTwBP4FDQUcBSsFOgVJBVgFZwV3BYYFlgWmBbUFxQXVBeUF9gYGBhYG
+ JwY3BkgGWQZqBnsGjAadBq8GwAbRBuMG9QcHBxkHKwc9B08HYQd0B4YHmQesB78H0gflB/gICw
+ gfCDIIRghaCG4IggiWCKoIvgjSCOcI+wkQCSUJOglPCWQJeQmPCaQJugnPCeUJ+woRCicKPQpU
+ CmoKgQqYCq4KxQrcCvMLCwsiCzkLUQtpC4ALmAuwC8gL4Qv5DBIMKgxDDFwMdQyODKcMwAzZDP
+ MNDQ0mDUANWg10DY4NqQ3DDd4N+A4TDi4OSQ5kDn8Omw62DtIO7g8JDyUPQQ9eD3oPlg+zD88P
+ 7BAJECYQQxBhEH4QmxC5ENcQ9RETETERTxFtEYwRqhHJEegSBxImEkUSZBKEEqMSwxLjEwMTIx
+ NDE2MTgxOkE8UT5RQGFCcUSRRqFIsUrRTOFPAVEhU0FVYVeBWbFb0V4BYDFiYWSRZsFo8WshbW
+ FvoXHRdBF2UXiReuF9IX9xgbGEAYZRiKGK8Y1Rj6GSAZRRlrGZEZtxndGgQaKhpRGncanhrFGu
+ wbFBs7G2MbihuyG9ocAhwqHFIcexyjHMwc9R0eHUcdcB2ZHcMd7B4WHkAeah6UHr4e6R8THz4f
+ aR+UH78f6iAVIEEgbCCYIMQg8CEcIUghdSGhIc4h+yInIlUigiKvIt0jCiM4I2YjlCPCI/AkHy
+ RNJHwkqyTaJQklOCVoJZclxyX3JicmVyaHJrcm6CcYJ0kneierJ9woDSg/KHEooijUKQYpOClr
+ KZ0p0CoCKjUqaCqbKs8rAis2K2krnSvRLAUsOSxuLKIs1y0MLUEtdi2rLeEuFi5MLoIuty7uLy
+ QvWi+RL8cv/jA1MGwwpDDbMRIxSjGCMbox8jIqMmMymzLUMw0zRjN/M7gz8TQrNGU0njTYNRM1
+ TTWHNcI1/TY3NnI2rjbpNyQ3YDecN9c4FDhQOIw4yDkFOUI5fzm8Ofk6Njp0OrI67zstO2s7qj
+ voPCc8ZTykPOM9Ij1hPaE94D4gPmA+oD7gPyE/YT+iP+JAI0BkQKZA50EpQWpBrEHuQjBCckK1
+ QvdDOkN9Q8BEA0RHRIpEzkUSRVVFmkXeRiJGZ0arRvBHNUd7R8BIBUhLSJFI10kdSWNJqUnwSj
+ dKfUrESwxLU0uaS+JMKkxyTLpNAk1KTZNN3E4lTm5Ot08AT0lPk0/dUCdQcVC7UQZRUFGbUeZS
+ MVJ8UsdTE1NfU6pT9lRCVI9U21UoVXVVwlYPVlxWqVb3V0RXklfgWC9YfVjLWRpZaVm4WgdaVl
+ qmWvVbRVuVW+VcNVyGXNZdJ114XcleGl5sXr1fD19hX7NgBWBXYKpg/GFPYaJh9WJJYpxi8GND
+ Y5dj62RAZJRk6WU9ZZJl52Y9ZpJm6Gc9Z5Nn6Wg/aJZo7GlDaZpp8WpIap9q92tPa6dr/2xXbK
+ 9tCG1gbbluEm5rbsRvHm94b9FwK3CGcOBxOnGVcfByS3KmcwFzXXO4dBR0cHTMdSh1hXXhdj52
+ m3b4d1Z3s3gReG54zHkqeYl553pGeqV7BHtje8J8IXyBfOF9QX2hfgF+Yn7CfyN/hH/lgEeAqI
+ EKgWuBzYIwgpKC9INXg7qEHYSAhOOFR4Wrhg6GcobXhzuHn4gEiGmIzokziZmJ/opkisqLMIuW
+ i/yMY4zKjTGNmI3/jmaOzo82j56QBpBukNaRP5GokhGSepLjk02TtpQglIqU9JVflcmWNJaflw
+ qXdZfgmEyYuJkkmZCZ/JpomtWbQpuvnByciZz3nWSd0p5Anq6fHZ+Ln/qgaaDYoUehtqImopaj
+ BqN2o+akVqTHpTilqaYapoum/adup+CoUqjEqTepqaocqo+rAqt1q+msXKzQrUStuK4trqGvFq
+ +LsACwdbDqsWCx1rJLssKzOLOutCW0nLUTtYq2AbZ5tvC3aLfguFm40blKucK6O7q1uy67p7wh
+ vJu9Fb2Pvgq+hL7/v3q/9cBwwOzBZ8Hjwl/C28NYw9TEUcTOxUvFyMZGxsPHQce/yD3IvMk6yb
+ nKOMq3yzbLtsw1zLXNNc21zjbOts83z7jQOdC60TzRvtI/0sHTRNPG1EnUy9VO1dHWVdbY11zX
+ 4Nhk2OjZbNnx2nba+9uA3AXcit0Q3ZbeHN6i3ynfr+A24L3hROHM4lPi2+Nj4+vkc+T85YTmDe
+ aW5x/nqegy6LzpRunQ6lvq5etw6/vshu0R7ZzuKO6070DvzPBY8OXxcvH/8ozzGfOn9DT0wvVQ
+ 9d72bfb794r4Gfio+Tj5x/pX+uf7d/wH/Jj9Kf26/kv+3P9t////4QBMRXhpZgAATU0AKgAAAA
+ gAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAMqADAAQAAAABAAAA
+ MgAAAAD/2wBDAAIBAQIBAQICAQICAgICAwUDAwMDAwYEBAMFBwYHBwcGBgYHCAsJBwgKCAYGCQ
+ 0JCgsLDAwMBwkNDg0MDgsMDAv/2wBDAQICAgMCAwUDAwULCAYICwsLCwsLCwsLCwsLCwsLCwsL
+ CwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwv/wAARCAAyADIDASIAAhEBAxEB/8QAHw
+ AAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQR
+ BRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRk
+ 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
+ L/8ArzT/APSUejR/hx9Aooor6k0P/9k=
+END:VCARD
diff --git a/tests/src/com/android/vcard/tests/VCardParserTests.java b/tests/src/com/android/vcard/tests/VCardParserTests.java
index 9b65593..2b63103 100644
--- a/tests/src/com/android/vcard/tests/VCardParserTests.java
+++ b/tests/src/com/android/vcard/tests/VCardParserTests.java
@@ -18,6 +18,7 @@ package com.android.vcard.tests;
import com.android.vcard.VCardInterpreter;
import com.android.vcard.VCardParser;
import com.android.vcard.VCardParser_V21;
+import com.android.vcard.VCardParser_V30;
import com.android.vcard.VCardProperty;
import com.android.vcard.exception.VCardException;
@@ -136,6 +137,38 @@ public class VCardParserTests extends AndroidTestCase {
}
/**
+ * Test vCard containing v3.0 line continuations and with non-standard
+ * line terminators \r\r\n coming from iOS 6.1.3. Tests to make sure the
+ * parser correctly skips the extra line terminators and still
+ * successfully concatenates the multi-line block.
+ */
+ public void testIosMultiline() throws IOException, VCardException {
+ InputStream inputStream = getContext().getResources().openRawResource(R.raw.v30_ios_613_multiline);
+ try {
+ VCardParser parser = new VCardParser_V30();
+ MockVCardInterpreter interpreter = new MockVCardInterpreter();
+ interpreter.addExpectedOrder(Order.START)
+ .addExpectedOrder(Order.START_ENTRY)
+ .addExpectedOrder(Order.PROPERTY_CREATED) // For VERSION
+ .addExpectedOrder(Order.PROPERTY_CREATED) // For N
+ .addExpectedOrder(Order.PROPERTY_CREATED) // For FN
+ .addExpectedOrder(Order.PROPERTY_CREATED) // For ORG
+ .addExpectedOrder(Order.PROPERTY_CREATED) // For item1
+ .addExpectedOrder(Order.PROPERTY_CREATED) // For TEL
+ .addExpectedOrder(Order.PROPERTY_CREATED) // For item2
+ .addExpectedOrder(Order.PROPERTY_CREATED) // For item3
+ .addExpectedOrder(Order.PROPERTY_CREATED) // For PHOTO
+ .addExpectedOrder(Order.END_ENTRY)
+ .addExpectedOrder(Order.END);
+ parser.addInterpreter(interpreter);
+ parser.parse(inputStream);
+ interpreter.verify();
+ } finally {
+ inputStream.close();
+ }
+ }
+
+ /**
* Tests if {@link VCardParser#parse(InputStream)} parses the whole vCard file and
* {@link VCardParser#parseOne(InputStream)} parses just first entry of a vCard file
* with multiple vCard entries.
@@ -206,4 +239,4 @@ public class VCardParserTests extends AndroidTestCase {
}
}
-} \ No newline at end of file
+}