skip BOM for source root detection (IDEA-77278, IDEA-98541)

This commit is contained in:
nik
2013-03-13 16:22:11 +04:00
parent 3069127870
commit b2fdf81153
6 changed files with 129 additions and 97 deletions
@@ -17,15 +17,15 @@ package com.intellij.ide.util.projectWizard.importSources.util;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.io.FileUtilRt;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.NullableFunction;
import com.intellij.util.text.CharsetUtil;
import com.intellij.util.text.StringFactory;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
import java.io.*;
public abstract class CommonSourceRootDetectionUtil<F> {
@@ -98,7 +98,7 @@ public abstract class CommonSourceRootDetectionUtil<F> {
@Override
protected CharSequence loadText(final File file) throws IOException {
return StringFactory.createShared(FileUtil.loadFileText(file));
return StringFactory.createShared(loadFileTextSkippingBom(file));
}
@Override
@@ -107,6 +107,18 @@ public abstract class CommonSourceRootDetectionUtil<F> {
}
};
private static char[] loadFileTextSkippingBom(File file) throws IOException {
//noinspection IOResourceOpenedButNotSafelyClosed
InputStream stream = CharsetUtil.inputStreamSkippingBOM(new BufferedInputStream(new FileInputStream(file)));
Reader reader = new InputStreamReader(stream);
try {
return FileUtilRt.loadText(reader, (int)file.length());
}
finally {
reader.close();
}
}
public static final CommonSourceRootDetectionUtil<VirtualFile> VIRTUAL_FILE = new CommonSourceRootDetectionUtil<VirtualFile>() {
@Override
@@ -0,0 +1,5 @@
package com;
public class MyClass {
}
@@ -54,6 +54,10 @@ public class JavaSourceRootDetectionTest extends PlatformTestCase {
doTest();
}
public void testFileWithBom() {
doTest("src", "");
}
private void doTest(String... expected) {
final String dirPath = JavaTestUtil.getJavaTestDataPath() + FileUtil.toSystemDependentName("/ide/sourceRootDetection/" + getTestName(true));
final File dir = new File(dirPath);
@@ -546,99 +546,11 @@ public class CharsetToolkit {
return charset;
}
private static final byte FF = (byte)0xff;
private static final byte FE = (byte)0xfe;
private static final byte EF = (byte)0xef;
private static final byte BB = (byte)0xbb;
private static final byte BF = (byte)0xbf;
/**
* @deprecated use {@link CharsetUtil#inputStreamSkippingBOM(java.io.InputStream)} instead
*/
@NotNull
public static InputStream inputStreamSkippingBOM(@NotNull InputStream stream) throws IOException {
assert stream.markSupported() :stream;
stream.mark(4);
boolean mustReset = true;
try {
int ret = stream.read();
if (ret == -1) {
return stream; // no bom
}
byte b0 = (byte)ret;
if (b0 != EF && b0 != FF && b0 != FE && b0 != 0) return stream; // no bom
ret = stream.read();
if (ret == -1) {
return stream; // no bom
}
byte b1 = (byte)ret;
if (b0 == FF && b1 == FE) {
stream.mark(2);
ret = stream.read();
if (ret == -1) {
return stream; // utf-16 LE
}
byte b2 = (byte)ret;
if (b2 != 0) {
return stream; // utf-16 LE
}
ret = stream.read();
if (ret == -1) {
return stream;
}
byte b3 = (byte)ret;
if (b3 != 0) {
return stream; // utf-16 LE
}
// utf-32 LE
mustReset = false;
return stream;
}
if (b0 == FE && b1 == FF) {
mustReset = false;
return stream; // utf-16 BE
}
if (b0 == EF && b1 == BB) {
ret = stream.read();
if (ret == -1) {
return stream; // no bom
}
byte b2 = (byte)ret;
if (b2 == BF) {
mustReset = false;
return stream; // utf-8 bom
}
// no bom
return stream;
}
if (b0 == 0 && b1 == 0) {
ret = stream.read();
if (ret == -1) {
return stream; // no bom
}
byte b2 = (byte)ret;
if (b2 != FE) {
return stream; // no bom
}
ret = stream.read();
if (ret == -1) {
return stream; // no bom
}
byte b3 = (byte)ret;
if (b3 != FF) {
return stream; // no bom
}
mustReset = false;
return stream; // UTF-32 BE
}
// no bom
return stream;
}
finally {
if (mustReset) stream.reset();
}
return CharsetUtil.inputStreamSkippingBOM(stream);
}
}
@@ -24,6 +24,7 @@ import com.intellij.util.Function;
import com.intellij.util.PathUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.DistinctRootsCollection;
import com.intellij.util.text.CharsetUtil;
import com.intellij.util.text.StringFactory;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -165,7 +166,7 @@ public class VfsUtilCore {
@NotNull
public static InputStream inputStreamSkippingBOM(@NotNull InputStream stream, @NotNull VirtualFile file) throws IOException {
return CharsetToolkit.inputStreamSkippingBOM(stream);
return CharsetUtil.inputStreamSkippingBOM(stream);
}
@NotNull
@@ -17,7 +17,10 @@ package com.intellij.util.text;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
/**
@@ -26,6 +29,11 @@ import java.io.UnsupportedEncodingException;
public class CharsetUtil {
public static final byte[] UTF8_BOM = {0xffffffef, 0xffffffbb, 0xffffffbf};
@NonNls public static final String UTF8 = "UTF-8";
private static final byte FF = (byte)0xff;
private static final byte FE = (byte)0xfe;
private static final byte EF = (byte)0xef;
private static final byte BB = (byte)0xbb;
private static final byte BF = (byte)0xbf;
public static boolean hasUTF8Bom(byte[] bom) {
return ArrayUtil.startsWith(bom, UTF8_BOM);
@@ -39,4 +47,94 @@ public class CharsetUtil {
throw new RuntimeException("UTF-8 must be supported", e);
}
}
@NotNull
public static InputStream inputStreamSkippingBOM(@NotNull InputStream stream) throws IOException {
assert stream.markSupported() :stream;
stream.mark(4);
boolean mustReset = true;
try {
int ret = stream.read();
if (ret == -1) {
return stream; // no bom
}
byte b0 = (byte)ret;
if (b0 != EF && b0 != FF && b0 != FE && b0 != 0) return stream; // no bom
ret = stream.read();
if (ret == -1) {
return stream; // no bom
}
byte b1 = (byte)ret;
if (b0 == FF && b1 == FE) {
stream.mark(2);
ret = stream.read();
if (ret == -1) {
return stream; // utf-16 LE
}
byte b2 = (byte)ret;
if (b2 != 0) {
return stream; // utf-16 LE
}
ret = stream.read();
if (ret == -1) {
return stream;
}
byte b3 = (byte)ret;
if (b3 != 0) {
return stream; // utf-16 LE
}
// utf-32 LE
mustReset = false;
return stream;
}
if (b0 == FE && b1 == FF) {
mustReset = false;
return stream; // utf-16 BE
}
if (b0 == EF && b1 == BB) {
ret = stream.read();
if (ret == -1) {
return stream; // no bom
}
byte b2 = (byte)ret;
if (b2 == BF) {
mustReset = false;
return stream; // utf-8 bom
}
// no bom
return stream;
}
if (b0 == 0 && b1 == 0) {
ret = stream.read();
if (ret == -1) {
return stream; // no bom
}
byte b2 = (byte)ret;
if (b2 != FE) {
return stream; // no bom
}
ret = stream.read();
if (ret == -1) {
return stream; // no bom
}
byte b3 = (byte)ret;
if (b3 != FF) {
return stream; // no bom
}
mustReset = false;
return stream; // UTF-32 BE
}
// no bom
return stream;
}
finally {
if (mustReset) stream.reset();
}
}
}