출처: http://codereview.stackexchange.com/questions/59428/validating-utf-8-byte-array
charset 이 불확실한 상황에서 여러 시스템에서 xml 기반 데이터를 주고 받다보면 charset 으로 인해 문베가 발생하곤한다.
A라는 시스템에서는 xml 은 utf-8 기반인데, 안에 있는 내용(BASE64 로 인코딩한)은 euc-kr 방식이고, B라는 시스템에서는 xml 은 utf-8 기반이고, 안에 있는 내용도 utf-8 방식이다.
위의 상황이라면 A와 B를 둘 다 만족시킬 수 있는 시스템을 만들기 위해서는 byte array 가 utf-8 인지 euc-kr 인지 구분이 필요하다.
(utf-8로 디코딩해야 하는 상황이라면 아래의 검사 후 utf-8이 아니라면 euc-kr 로 다시 디코딩)
참고했던 페이지는 Java 7 기반으로 되어 있어서 Java 6 기반으로 바꾸어보았다.
in Java 6
###java
public class ValidateUtf8 {
/**
* Returns the number of UTF-8 characters, or -1 if the array does not
* contain a valid UTF-8 string. Overlong encodings, null characters,
* invalid Unicode values, and surrogates are accepted.
*
* @param bytes byte array to check length
* @return length
*/
public static int charLength(byte[] bytes) {
int charCount = 0, expectedLen;
for (int i = 0; i < bytes.length; i++) {
charCount++;
// Lead byte analysis
if ((bytes[i] & Integer.parseInt("10000000", 2)) == Integer.parseInt("00000000", 2)) {
continue;
} else if ((bytes[i] & Integer.parseInt("11100000", 2)) == Integer.parseInt("11000000", 2)) {
expectedLen = 2;
} else if ((bytes[i] & Integer.parseInt("11110000", 2)) == Integer.parseInt("11100000", 2)) {
expectedLen = 3;
} else if ((bytes[i] & Integer.parseInt("11111000", 2)) == Integer.parseInt("11110000", 2)) {
expectedLen = 4;
} else if ((bytes[i] & Integer.parseInt("11111100", 2)) == Integer.parseInt("11111000", 2)) {
expectedLen = 5;
} else if ((bytes[i] & Integer.parseInt("11111110", 2)) == Integer.parseInt("11111100", 2)) {
expectedLen = 6;
} else {
return -1;
}
// Count trailing bytes
while (--expectedLen > 0) {
if (++i >= bytes.length) {
return -1;
}
if ((bytes[i] & Integer.parseInt("11000000", 2)) != Integer.parseInt("10000000", 2)) {
return -1;
}
}
}
return charCount;
}
/**
* Validate a UTF-8 byte array
*
* @param bytes byte array to validate
* @return true if UTF-8
*/
public static boolean validate(byte[] bytes) {
return (charLength(bytes) != -1);
}
}
in Java 7 이상
### java
public class ValidateUtf8 {
/**
* Returns the number of UTF-8 characters, or -1 if the array does not
* contain a valid UTF-8 string. Overlong encodings, null characters,
* invalid Unicode values, and surrogates are accepted.
*
* @param bytes byte array to check length
* @return length
*/
public static int charLength(byte[] bytes) {
int charCount = 0, expectedLen;
for (int i = 0; i < bytes.length; i++) {
charCount++;
// Lead byte analysis
if ((bytes[i] & 0b10000000) == 0b00000000) {
continue;
} else if ((bytes[i] & 0b11100000) == 0b11000000) {
expectedLen = 2;
} else if ((bytes[i] & 0b11110000) == 0b11100000) {
expectedLen = 3;
} else if ((bytes[i] & 0b11111000) == 0b11110000) {
expectedLen = 4;
} else if ((bytes[i] & 0b11111100) == 0b11111000) {
expectedLen = 5;
} else if ((bytes[i] & 0b11111110) == 0b11111100) {
expectedLen = 6;
} else {
return -1;
}
// Count trailing bytes
while (--expectedLen > 0) {
if (++i >= bytes.length) {
return -1;
}
if ((bytes[i] & 0b11000000) != 0b10000000) {
return -1;
}
}
}
return charCount;
}
/**
* Validate a UTF-8 byte array
*
* @param bytes byte array to validate
* @return true if UTF-8
*/
public static boolean validate(byte[] bytes) {
return (charLength(bytes) != -1);
}
}