detect truncated/bad encoded xml files as application/xml
MODIFY
tika-core/src/main/java/org/apache/tika/detect/XmlRootExtractor.java
tika-core/src/main/java/org/apache/tika/detect/XmlRootExtractor.java
package org.apache.tika.detect;
import java.io.ByteArrayInputStream;
+import java.io.CharConversionException;
import java.io.InputStream;
+import java.util.Arrays;
import javax.xml.namespace.QName;
import org.apache.commons.io.input.CloseShieldInputStream;
@@ -39,20 +41,45 @@ public class XmlRootExtractor {
private static final ParseContext EMPTY_CONTEXT = new ParseContext();
public QName extractRootElement(byte[] data) {
- return extractRootElement(new ByteArrayInputStream(data));
+ // this loop should be very rare
+ while (true) {
+ try {
+ return extractRootElement(new ByteArrayInputStream(data), true);
+ } catch (MalformedCharException e) {
+ // see TIKA-3596, try to handle truncated/bad encoded XML files
+ int newLen = data.length / 2;
+ if (newLen % 2 == 1) {
+ newLen--;
+ }
+ if (newLen > 0) {
+ data = Arrays.copyOf(data, newLen);
+ } else {
+ break;
+ }
+ }
+ }
+ return null;
}
/**
* @since Apache Tika 0.9
*/
public QName extractRootElement(InputStream stream) {
+ return extractRootElement(stream, false);
+ }
+
+ private QName extractRootElement(InputStream stream, boolean throwMalformed) {
ExtractorHandler handler = new ExtractorHandler();
try {
XMLReaderUtils.parseSAX(new CloseShieldInputStream(stream),
new OfflineContentHandler(handler), EMPTY_CONTEXT);
} catch (SecurityException e) {
throw e;
- } catch (Exception ignore) {
+ } catch (Exception e) {
+ if (throwMalformed && (e instanceof CharConversionException
+ || e.getCause() instanceof CharConversionException)) {
+ throw new MalformedCharException(e);
+ }
}
return handler.rootElement;
}
@@ -70,4 +97,12 @@ public class XmlRootExtractor {
}
+ private static class MalformedCharException extends RuntimeException {
+
+ public MalformedCharException(Exception e) {
+ super(e);
+ }
+
+ }
+
}

MODIFY
tika-core/src/test/java/org/apache/tika/mime/MimeDetectionTest.java
tika-core/src/test/java/org/apache/tika/mime/MimeDetectionTest.java
@@ -78,6 +78,9 @@ public class MimeDetectionTest {
//test GCMD Directory Interchange Format (.dif) TIKA-1561
testFile("application/dif+xml", "brwNIMS_2014.dif");
+
+ // truncated xml should still be detected as xml, See TIKA-3596
+ testFile("application/xml", "truncated-utf16-xml.xyz");
}
@Test

ADD
tika-core/src/test/resources/org/apache/tika/mime/truncated-utf16-xml.xyz
tika-core/src/test/resources/org/apache/tika/mime/truncated-utf16-xml.xyz
Binary files /dev/null and b/tika-core/src/test/resources/org/apache/tika/mime/truncated-utf16-xml.xyz differ

TIKA-3596: detect truncated/bad encoded xml files as application/xml