/*
Copyright (C) 2004-2009 Stewart Gordon.

This software is provided 'as-is', without any express or implied
warranty.  In no event will the author be held liable for any damages
arising from the use of this software.

Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute
it freely, subject to the following restrictions:

- The origin of this software must not be misrepresented; you must
  not claim that you wrote the original software.  If you use this
  software in a product, an acknowledgment in the product
  documentation would be appreciated but is not required.
- Altered source versions must be plainly marked as such, and must
  not be misrepresented as being the original software.
- This notice may not be removed or altered from any source
  distribution.
*/
function CodePage(name, chars) {
	this.name = name;
	this.chars = chars;
	
	this.encode = function(text, swallowErrors) {
		var result = new Array;
		for (i in text) {
			if (text.charCodeAt(i) < 128) {
				result[result.length] = text.charCodeAt(i);
			} else if (text.charAt(i) == '�') {
				result[result.length] = -1;
			} else {
				var c = this.chars.indexOf(text.charAt(i));
				if (c < 0) {
					if (swallowErrors) {
						result[result.length] = -1;
					} else {
						throw 'character not in codepage';
					}
				} else {
					result[result.length] = 128 + c;
				}
			}
		}
		return result;
	}
	
	this.decode = function(bytes) {
		var result = '';
		for (i in bytes) {
			if (bytes[i] < 128) {
				result += String.fromCharCode(bytes[i]);
			} else {
				result += this.chars[bytes[i] - 128];
			}
		}
		return result;
	}
}

var utf8 = {
	name:
		'UTF-8',
	encode:
		function(text) {
			var result = new Array;
			var index = 0;
			for (i in text) {
				cp = text.charCodeAt(i);
				if (cp <= 0x7F) {
					// 0xxxxxxx
					result[index] = cp;
					index++;
				} else if (cp <= 0x7FF) {
					// 110xxxxx 10xxxxxx
					result[index] = 0xC0 | (cp >> 6);
					result[index+1] = 0x80 | (cp & 0x3F);
					index += 2;
				} else if (cp <= 0xFFFF) {
					// 1110xxxx 10xxxxxx 10xxxxxx
					result[index] = 0xE0 | (cp >> 12);
					result[index+1] = 0x80 | ((cp >> 6) & 0x3F);
					result[index+2] = 0x80 | (cp & 0x3F);
					index += 3;
				} else {
					// 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
					result[index] = 0xF0 | (cp >> 18);
					result[index+1] = 0x80 | ((cp >> 12) & 0x3F);
					result[index+2] = 0x80 | ((cp >> 6) & 0x3F);
					result[index+3] = 0x80 | (cp & 0x3F);
					index += 4;
				}
			}
			return result;
		},
	decode:
		function(bytes, swallowErrors) {
			var result = '';
			for (var i = 0; i < bytes.length; i++) {
				try {
					if (bytes[i] < 0x80) {
						// 0xxxxxxx
						result += String.fromCharCode(bytes[i]);

					} else if (bytes[i] < 0xC0 || bytes[i] >= 0xF8) {
						throw 'invalid UTF-8 lead byte';

					} else if (bytes[i] < 0xC2) {
						throw 'overlong UTF-8 sequence';

					} else if (bytes[i] < 0xE0) {
						// 110xxxxx 10xxxxxx
						if ((bytes[i+1] & 0xC0) != 0x80) throw 'invalid UTF-8 continuation byte';
						result += String.fromCharCode(((bytes[i] & 0x1F) << 6) | (bytes[i+1] & 0x3F));
						i++;

					} else if (bytes[i] < 0xF0) {
						// 1110xxxx 10xxxxxx 10xxxxxx
						if ((bytes[i+1] & 0xC0) != 0x80 || (bytes[i+2] & 0xC0) != 0x80) {
							throw 'invalid UTF-8 continuation byte';
						}
						if (bytes[i] == 0xE0 && bytes[i+1] < 0xA0) throw 'overlong UTF-8 sequence';
						result += String.fromCharCode(((bytes[i] & 0x0F) << 12) | ((bytes[i+1] & 0x3F) << 6) | (bytes[i+2] & 0x3F));
						i += 2;

					} else {
						// 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
						if ((bytes[i+1] & 0xC0) != 0x80 || (bytes[i+2] & 0xC0) != 0x80
							  || (bytes[i+3] & 0xC0) != 0x80) {
							throw 'invalid UTF-8 continuation byte';
						}
						if (bytes[i] == 0xF0 && bytes[i+1] < 0x90) throw 'overlong UTF-8 sequence';
						result += String.fromCharCode(
							((bytes[i] & 0x07) << 18) | ((bytes[i+1] & 0x3F) << 12)
						  | ((bytes[i+2] & 0x3F) << 6) | (bytes[i+3] & 0x3F));
						i += 3;
					}
				} catch (e) {
					if (swallowErrors) {
						result += '�';
						i++;
					} else {
						throw e;
					}
				}
			}
			return result;
		}
};

var codePages = [
	utf8,
	new CodePage('ISO 8859-1',   '�������������������������������� ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ'),
	new CodePage('ISO 8859-15',  '�������������������������������� ¡¢£€¥Š§š©ª«¬­®¯°±²³Žµ¶·ž¹º»ŒœŸ¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ'),
	new CodePage('Windows 1250', '€‚„…†‡‰Š‹ŚŤŽŹ‘’“”•–—™š›śťžź ˇ˘Ł¤Ą¦§¨©Ş«¬­®Ż°±˛ł´µ¶·¸ąş»Ľ˝ľżŔÁÂĂÄĹĆÇČÉĘËĚÍÎĎĐŃŇÓÔŐÖ×ŘŮÚŰÜÝŢßŕáâăäĺćçčéęëěíîďđńňóôőö÷řůúűüýţ˙'),
	new CodePage('Windows 1252', '€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ'),
	new CodePage('IBM 437',      'ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñÑªº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ '),
	new CodePage('IBM 850',      'ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜø£Ø×ƒáíóúñÑªº¿®¬½¼¡«»░▒▓│┤ÁÂÀ©╣║╗╝¢¥┐└┴┬├─┼ãÃ╚╔╩╦╠═╬¤ðÐÊËÈıÍÎÏ┘┌█▄¦Ì▀ÓßÔÒõÕµþÞÚÛÙýÝ¯´­±‗¾¶§÷¸°¨·¹³²■ '),
	new CodePage('IBM 852',      'ÇüéâäůćçłëŐőîŹÄĆÉĹĺôöĽľŚśÖÜŤťŁ×čáíóúĄąŽžĘę¬źČş«»░▒▓│┤ÁÂĚŞ╣║╗╝Żż┐└┴┬├─┼Ăă╚╔╩╦╠═╬¤đĐĎËďŇÍÎě┘┌█▄ŢŮ▀ÓßÔŃńňŠšŔÚŕŰýÝţ´­˝˛ˇ˘§÷¸°¨˙űŘř■ '),
];

