aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain
diff options
context:
space:
mode:
authorVincent Breitmoser <valodim@mugenguild.com>2016-02-22 21:12:36 +0100
committerVincent Breitmoser <valodim@mugenguild.com>2016-02-22 21:58:31 +0100
commitdaf243082c6cd7fb7f518bfbf0acf9acafaa27d1 (patch)
tree44b4f3ba716e943d72f51f24504355b1b7e383a2 /OpenKeychain
parentbdae99c0847556dd8103f172fc1836eb83ae4c4a (diff)
downloadopen-keychain-daf243082c6cd7fb7f518bfbf0acf9acafaa27d1.tar.gz
open-keychain-daf243082c6cd7fb7f518bfbf0acf9acafaa27d1.tar.bz2
open-keychain-daf243082c6cd7fb7f518bfbf0acf9acafaa27d1.zip
externalize CharsetVerifier, add looksLikeText to OpenPgpMetadata object
Diffstat (limited to 'OpenKeychain')
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CharsetVerifier.java122
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/InputDataOperation.java94
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java19
-rw-r--r--OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/InputDataOperationTest.java4
4 files changed, 152 insertions, 87 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CharsetVerifier.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CharsetVerifier.java
new file mode 100644
index 000000000..5d63ced22
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CharsetVerifier.java
@@ -0,0 +1,122 @@
+package org.sufficientlysecure.keychain.operations;
+
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
+
+import android.content.ClipDescription;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+
+public class CharsetVerifier {
+
+ private final ByteBuffer bufWrap;
+ private final CharBuffer dummyOutput;
+
+ private final CharsetDecoder charsetDecoder;
+
+ private boolean isFinished;
+ private boolean isFaulty;
+ private boolean isGuessed;
+ private boolean isPossibleTextMimeType;
+ private boolean isTextMimeType;
+ private String charset;
+
+ public CharsetVerifier(@NonNull byte[] buf, String mimeType, @Nullable String charset) {
+
+ isPossibleTextMimeType = ClipDescription.compareMimeTypes(mimeType, "application/octet-stream")
+ || ClipDescription.compareMimeTypes(mimeType, "application/x-download")
+ || ClipDescription.compareMimeTypes(mimeType, "text/*");
+ if (!isPossibleTextMimeType) {
+ charsetDecoder = null;
+ bufWrap = null;
+ dummyOutput = null;
+ return;
+ }
+ isTextMimeType = ClipDescription.compareMimeTypes(mimeType, "text/*");
+
+ bufWrap = ByteBuffer.wrap(buf);
+ dummyOutput = CharBuffer.allocate(buf.length);
+
+ // the charset defaults to us-ascii, but we want to default to utf-8
+ if (charset == null || "us-ascii".equals(charset)) {
+ charset = "utf-8";
+ isGuessed = true;
+ } else {
+ isGuessed = false;
+ }
+ this.charset = charset;
+
+ charsetDecoder = Charset.forName(charset).newDecoder();
+ charsetDecoder.onMalformedInput(CodingErrorAction.REPORT);
+ charsetDecoder.onUnmappableCharacter(CodingErrorAction.REPORT);
+ charsetDecoder.reset();
+ }
+
+ public void write(int pos, int len) {
+ if (isFinished) {
+ throw new IllegalStateException("cannot write again after reading charset status!");
+ }
+ if (isFaulty || bufWrap == null) {
+ return;
+ }
+ bufWrap.rewind();
+ bufWrap.position(pos);
+ bufWrap.limit(len);
+ dummyOutput.rewind();
+ CoderResult result = charsetDecoder.decode(bufWrap, dummyOutput, false);
+ if (result.isError()) {
+ isFaulty = true;
+ }
+ }
+
+ private void finishIfNecessary() {
+ if (isFinished || isFaulty || bufWrap == null) {
+ return;
+ }
+ isFinished = true;
+ bufWrap.rewind();
+ bufWrap.limit(0);
+ dummyOutput.rewind();
+ CoderResult result = charsetDecoder.decode(bufWrap, dummyOutput, true);
+ if (result.isError()) {
+ isFaulty = true;
+ }
+ }
+
+ public boolean isCharsetFaulty() {
+ finishIfNecessary();
+ return isFaulty;
+ }
+
+ public boolean isCharsetGuessed() {
+ finishIfNecessary();
+ return isGuessed;
+ }
+
+ public String getCharset() {
+ finishIfNecessary();
+ if (!isPossibleTextMimeType || (isGuessed && isFaulty)) {
+ return null;
+ }
+ return charset;
+ }
+
+ public String getMaybeFaultyCharset() {
+ return charset;
+ }
+
+ public boolean isDefinitelyBinary() {
+ finishIfNecessary();
+ return !isTextMimeType && (!isPossibleTextMimeType || (isGuessed && isFaulty));
+ }
+
+ public boolean isProbablyText() {
+ return isTextMimeType || isPossibleTextMimeType && (!isGuessed || !isFaulty);
+ }
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/InputDataOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/InputDataOperation.java
index 80f9d6368..ff9377581 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/InputDataOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/InputDataOperation.java
@@ -23,13 +23,6 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.nio.ByteBuffer;
-import java.nio.CharBuffer;
-import java.nio.charset.Charset;
-import java.nio.charset.CharsetDecoder;
-import java.nio.charset.CoderResult;
-import java.nio.charset.CodingErrorAction;
-import java.nio.charset.UnsupportedCharsetException;
import java.util.ArrayList;
import android.content.ClipDescription;
@@ -75,14 +68,9 @@ import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
public class InputDataOperation extends BaseOperation<InputDataParcel> {
private final byte[] buf = new byte[256];
- private final ByteBuffer bufWrap;
- private final CharBuffer dummyOutput;
public InputDataOperation(Context context, ProviderHelper providerHelper, Progressable progressable) {
super(context, providerHelper, progressable);
-
- bufWrap = ByteBuffer.wrap(buf);
- dummyOutput = CharBuffer.allocate(256);
}
Uri mSignedDataUri;
@@ -338,83 +326,37 @@ public class InputDataOperation extends BaseOperation<InputDataParcel> {
throw new IOException("Error getting file for writing!");
}
- boolean isPossibleTextMimeType = ClipDescription.compareMimeTypes(mimeType, "application/octet-stream")
- || ClipDescription.compareMimeTypes(mimeType, "application/x-download")
- || ClipDescription.compareMimeTypes(mimeType, "text/*");
-
// If this data looks like text, we pipe the incoming data into a charset
// decoder, to see if the data is legal for the assumed charset.
- String charset;
- boolean charsetIsFaulty;
- boolean charsetIsGuessed;
- CharsetDecoder charsetDecoder = null;
- if (isPossibleTextMimeType) {
- charset = bd.getCharset();
- // the charset defaults to us-ascii, but we want to default to utf-8
- if (charset == null || "us-ascii".equals(charset)) {
- charset = "utf-8";
- charsetIsGuessed = true;
- } else {
- charsetIsGuessed = false;
- }
-
- try {
- charsetDecoder = Charset.forName(charset).newDecoder();
- charsetDecoder.onMalformedInput(CodingErrorAction.REPORT);
- charsetDecoder.onUnmappableCharacter(CodingErrorAction.REPORT);
- charsetDecoder.reset();
- charsetIsFaulty = false;
- } catch (UnsupportedCharsetException e) {
- charsetIsFaulty = true;
- }
- } else {
- charsetIsFaulty = true;
- charsetIsGuessed = false;
- charset = null;
- }
+ String charset = bd.getCharset();
+ CharsetVerifier charsetVerifier = new CharsetVerifier(buf, mimeType, charset);
int totalLength = 0;
do {
totalLength += len;
out.write(buf, 0, len);
-
- if (isPossibleTextMimeType && !charsetIsFaulty) {
- bufWrap.rewind();
- bufWrap.limit(len);
- dummyOutput.rewind();
- CoderResult result = charsetDecoder.decode(bufWrap, dummyOutput, false);
- if (result.isError()) {
- charsetIsFaulty = true;
- }
- }
+ charsetVerifier.write(0, len);
} while ((len = is.read(buf)) > 0);
- if (!charsetIsFaulty) {
- bufWrap.rewind();
- bufWrap.limit(0);
- dummyOutput.rewind();
- CoderResult result = charsetDecoder.decode(bufWrap, dummyOutput, true);
- if (result.isError()) {
- charsetIsFaulty = true;
- }
- }
+ log.add(LogType.MSG_DATA_MIME_LENGTH, 3, Long.toString(totalLength));
- if (isPossibleTextMimeType) {
- if (charsetIsFaulty && charsetIsGuessed) {
- log.add(LogType.MSG_DATA_MIME_CHARSET_UNKNOWN, 3, charset);
- charset = null;
- } else if (charsetIsFaulty) {
- log.add(LogType.MSG_DATA_MIME_CHARSET_FAULTY, 3, charset);
- } else if (charsetIsGuessed) {
- log.add(LogType.MSG_DATA_MIME_CHARSET_GUESS, 3, charset);
+ OpenPgpMetadata metadata;
+ if (charsetVerifier.isDefinitelyBinary()) {
+ metadata = new OpenPgpMetadata(mFilename, mimeType, 0L, totalLength);
+ } else {
+ if (charsetVerifier.isCharsetFaulty() && charsetVerifier.isCharsetGuessed()) {
+ log.add(LogType.MSG_DATA_MIME_CHARSET_UNKNOWN, 3, charsetVerifier.getMaybeFaultyCharset());
+ } else if (charsetVerifier.isCharsetFaulty()) {
+ log.add(LogType.MSG_DATA_MIME_CHARSET_FAULTY, 3, charsetVerifier.getCharset());
+ } else if (charsetVerifier.isCharsetGuessed()) {
+ log.add(LogType.MSG_DATA_MIME_CHARSET_GUESS, 3, charsetVerifier.getCharset());
} else {
- log.add(LogType.MSG_DATA_MIME_CHARSET, 3, charset);
+ log.add(LogType.MSG_DATA_MIME_CHARSET, 3, charsetVerifier.getCharset());
}
- }
-
- log.add(LogType.MSG_DATA_MIME_LENGTH, 3, Long.toString(totalLength));
- OpenPgpMetadata metadata = new OpenPgpMetadata(mFilename, mimeType, 0L, totalLength, charset);
+ metadata = new OpenPgpMetadata(mFilename, mimeType, 0L, totalLength,
+ charsetVerifier.getCharset(), charsetVerifier.isProbablyText());
+ }
out.close();
outputUris.add(uri);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java
index c4755c7c5..59ba8df5f 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java
@@ -377,9 +377,11 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
originalFilename = "";
}
String mimeType = null;
+ boolean looksLikeText;
if (literalData.getFormat() == PGPLiteralData.TEXT
|| literalData.getFormat() == PGPLiteralData.UTF8) {
mimeType = "text/plain";
+ looksLikeText = true;
} else {
// try to guess from file ending
String extension = MimeTypeMap.getFileExtensionFromUrl(originalFilename);
@@ -390,6 +392,7 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
if (mimeType == null) {
mimeType = "application/octet-stream";
}
+ looksLikeText = false;
}
if (!"".equals(originalFilename)) {
@@ -414,11 +417,9 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
}
metadata = new OpenPgpMetadata(
- originalFilename,
- mimeType,
+ originalFilename, mimeType,
literalData.getModificationTime().getTime(),
- originalSize == null ? 0 : originalSize,
- charset);
+ originalSize == null ? 0 : originalSize, charset, false);
log.add(LogType.MSG_DC_OK_META_ONLY, indent);
DecryptVerifyResult result =
@@ -490,8 +491,8 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
log.add(LogType.MSG_DC_CLEAR_META_MIME, indent + 1, mimeType);
- metadata = new OpenPgpMetadata(
- originalFilename, mimeType, literalData.getModificationTime().getTime(), alreadyWritten, charset);
+ metadata = new OpenPgpMetadata(originalFilename, mimeType, literalData.getModificationTime().getTime(),
+ alreadyWritten, charset, looksLikeText);
indent -= 1;
@@ -873,11 +874,7 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
log.add(LogType.MSG_DC_OK, indent);
- OpenPgpMetadata metadata = new OpenPgpMetadata(
- "",
- "text/plain",
- -1,
- clearText.length);
+ OpenPgpMetadata metadata = new OpenPgpMetadata("", "text/plain", -1, clearText.length, "utf-8", true);
DecryptVerifyResult result = new DecryptVerifyResult(DecryptVerifyResult.RESULT_OK, log);
result.setSignatureResult(signatureChecker.getSignatureResult());
diff --git a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/InputDataOperationTest.java b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/InputDataOperationTest.java
index 0464bf508..013465c44 100644
--- a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/InputDataOperationTest.java
+++ b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/pgp/InputDataOperationTest.java
@@ -162,6 +162,7 @@ public class InputDataOperationTest {
OpenPgpMetadata metadata = result.mMetadata.get(0);
Assert.assertEquals("text/plain", metadata.getMimeType());
Assert.assertEquals("utf-8", metadata.getCharset());
+ Assert.assertTrue("data should be looksLikeText", metadata.isLooksLikeText());
metadata = result.mMetadata.get(1);
Assert.assertEquals("text/testvalue", metadata.getMimeType());
@@ -213,6 +214,7 @@ public class InputDataOperationTest {
OpenPgpMetadata metadata = result.mMetadata.get(0);
Assert.assertEquals("text/plain", metadata.getMimeType());
+ Assert.assertTrue("data should be looksLikeText", metadata.isLooksLikeText());
Assert.assertNull("charset was bad so it should not be set", metadata.getCharset());
Assert.assertTrue("faulty charset should have been detected",
@@ -234,6 +236,7 @@ public class InputDataOperationTest {
OpenPgpMetadata metadata = result.mMetadata.get(0);
Assert.assertEquals("text/plain", metadata.getMimeType());
+ Assert.assertTrue("data should be looksLikeText", metadata.isLooksLikeText());
Assert.assertEquals("charset should be set since it was guessed and not faulty",
"utf-8", metadata.getCharset());
@@ -256,6 +259,7 @@ public class InputDataOperationTest {
OpenPgpMetadata metadata = result.mMetadata.get(0);
Assert.assertEquals("application/octet-stream", metadata.getMimeType());
+ Assert.assertTrue("data should be looksLikeText", metadata.isLooksLikeText());
Assert.assertEquals("charset should be set since it was guessed and not faulty",
"utf-8", metadata.getCharset());