/* -*- mode: c++; tab-width: 4; c-basic-offset: 4 -*- */
/*
 * Copyright (C) 2005 Atmark <atmarkat _AT_ msn _DOT_ com>
 *                    AGAWA Koji <i _AT_ atty _DOT_ jp>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the 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 program 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include <cstdio>

#include "textencoding.h"

/*!
	@brief	漢字コードを識別する
	
	参考：http://www-cms.phys.s.u-tokyo.ac.jp/~naoki/CIPINTRO/CCGI/kanjicod.html
	UTF-8はShift JISと重るので、速度を多少犠牲にして2度走査している
	@see	isUTF8()
*/
int TextEncoding::detectEncoding(const char *str)
{
	if (isUTF8(str))
		return UTF_8;
	
	for(const unsigned char *s = (unsigned char*)str; *s; s++)
	{
		if (*s == 0x1b && *(s+1) == '$')
			return  ISO_2022_JP;
		if (*s < 0x80 )
			continue;
		if (0x81 <= *s && *s <= 0x9F)
			return Shift_JIS;
		if (0xA1 <= *s && *s <= 0xDF)
			return  EUC_JP;
		if (*(s+1) <= 0xA0)
			return Shift_JIS;
	}
	return ASCII;
}

/*!
	@brief	UTF-8テキストかどうか
	
	参考：http://www.gprj.net/dev/tips/other/kanji.shtml
	@see	detectEncoding()
*/
bool TextEncoding::isUTF8(const char *str)
{
	unsigned char length = 0;	// 文字列長
	
	for (const unsigned char *s = (unsigned char*)str; *s; s++)
	{
		// ASCII
		// if (0x00 <= *s && *s <= 0x7f)
		if (*s <= 0x7f)
			continue;
		// UTF-8の1byte目チェック
		else if (0xc0 <= *s && *s <= 0xfd)
		{
			// 文字長の整合性チェック
			if (length != 0)
				return false;
			
			// 文字長の取得
			if ((*s & 0xfc) == 0xfc)	// 11111100
				length = 5;
			else if ((*s & 0xf8) == 0xf8)	// 11111000
				length = 4;
			else if ((*s & 0xf0) == 0xf0)	// 11110000
				length = 3;
			else if ((*s & 0xe0) == 0xe0)	// 11100000
				length = 2;
			else if ((*s & 0xc0) == 0xc0)	// 11000000
				length = 1;
			else
				length = 0;
		}
		// 2byte目チェック
		else if (0x80 <= *s && *s <= 0xbf)
			length--;
		else
			return false;
	}
	
	return true;
}

// UTF-8は文字長も関係あるので、切所を考える必要あり
int TextEncoding::detectFileEncoding(const char *file, unsigned int limit)
{
	FILE *f = fopen(file, "rb");
	
	if (f == NULL)
		return Unknown;
	
	char buf[limit];
	buf[fread(buf, sizeof(char), limit - 1, f)] = '\0';
	
	fclose(f);
	
	return detectEncoding(buf);
}
