/* Copyright (C) 2007 Viavansi Servicios Avanzados para las Instituciones S.L. (VIAVANSI) Se permite la libre distribución y modificación de esta librería bajo los términos de la licencia GPL siempre que se indique de forma clara la autoría de Servicios Avanzados para las Instituciones S.L. (VIAVANSI). Para usos comerciales de este software contacte con info@viavansi.com. This library is free software; you can redistribute it and/or modify it under the terms of the GPL GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. For any commercial use of this software contact info@viavansi.com. ******************************************************************** Encoding: UTF-8 Cadena de comprobación de encoding: 'El veloz murciélago hindú comía feliz cardillo y kiwi.' 'La cigüeña tocaba el saxofón detrás del palenque de paja.' */ import java.io.DataInputStream; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; /** * Recorte de código para comprobar si un flujo de datos esta en formato UTF-8. * @author Félix García Borrego (fgarcia@viavansi.com) * */ public class TestEncoding { /** * Detecta si el flujo de datos indicado es UTF-8. * Basándose en la especificación RFC 3629 (http://ietf.org/rfc/rfc3629) * * @param input * @return */ public boolean isUTF8(InputStream inputStream) { DataInputStream input = new DataInputStream(inputStream); // Recorremos el fichero y comprobamos que todos los bytes del mismo // cumplen el formato UTF-8 byte byteActual; try { // Mientras no llegemos al final del fichero while (true) { // El fin del bucle se produce con EOFException byteActual = input.readByte(); // El formato UTF-8 coincide con el ISO en los 128 primero caracteres. // pero para valores superiores a 128 (1000 0000) 0x40 se utilizan de 2 a 4 bytes // 0x80 --> la mascara es 0111 1111 ( 0x7F) Si es igual al 1111 1111 if (((byte) (byteActual | 0x7F)) == (byte) 0xFF) { // Los bytes menores coinciden con el formato ISO y ASCII , // pero los valores mayores de 128 deben ajustarse al tamaño // de 2,3,4 bytes según lo requerido // Comprobación para caracteres UTF-8 de 2 bytes Formato requerido: 110xxxxx 10xxxxxx // Comprobamos si empieza por 110xxxxx 110xxxxx --> la mascara que busco es 00011111 --> hexadecimal : 0x1F // El valor procesado debe ser igual a 110xxxxx --> 11011111 -> 0xDF if (((byte) (byteActual | 0x1F)) == ((byte) 0xDF)) { // Estamos en una estructura que tiene 2 bytes. byteActual = input.readByte(); // Comprobamos si empieza por 10xxxxxx 10xxxxxx --> la mascara que busco es 10111111 --> a 0xBF // El valor procesado debe ser igual a 10xxxxxx --> 10111111 -> 0xBF if (((byte) (byteActual | 0xBF)) == (byte) 0xBF) { // OK, el caracter es correcto } else { // No cumple con la condición de segundo byte 10xxxxxx return false; } } else { // El segundo caracter tiene que cumplir 10xxxxxxx, en otro caso es un error return false; // 11110011 } }else{ // TODO : Por ahora solo se consideran un subconjunto // UTF-8 ( para caracteres de 1 o 2 bytes , considerando // erroneos los de 3 o 4 bytes. ( Por ejemplo quedan fuera del reconocedor el Tibetano :p } } } catch (EOFException eof) { //log.debug("Procesado correctamente."); } catch (IOException e) { //log.warn(e.getMessage()); return false; } return true; } }