もどる TOP

HTML5製バイナリエディタ

  • スマホには対応してません。読み込めるのは65,536バイトまでのファイルまでです。
  • ASCIIで印字不可能な文字は、すべて灰色の「.」で表示されます。

00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
0123456789abcdef
ダウンロード
JavaScriptソース
  • 2018-06-26 ver1.0.0 公開
javascript
window.addEventListener('load', () => {
	var rowNumberElem = document.getElementById('main_row-number');
	var binElem = document.getElementById('main_bin');
	var strElem = document.getElementById('main_string');
	Krbin.init();
	//Krbin.loadByURI('./sample.dat', update);

	document.getElementById('file-select').addEventListener('change', (event) => {
		if (event.target.files[0] !== undefined) {
			var file = event.target.files[0];
			if (file.size > 65536) {
				alert('65536バイト以上のファイルです。読み込みに失敗しました。');
			} else {
				Krbin.loadByFile(file, update);
			}
		}
	});
	binElem.addEventListener('keydown', (event) => {
		if ((event.keyCode < 37 || 40 < event.keyCode) // !arrow
			&& event.keyCode != 9 // !tab
		) {
			event.preventDefault();
		}
	});
	binElem.addEventListener('keyup', (event) => {
		var pos = binElem.selectionStart;
		if (/^[0-9a-fA-F]$/.test(event.key)) {
			var index = ~~(pos / 3);
			var surplus = pos % 3;
			var digits;
			if (surplus === 0) {
				digits = 2;
			} else if (surplus === 1) {
				digits = 1;
			} else if (surplus === 2) {
				digits = 2;
				index += 1;
				pos += 1;
			}
			Krbin.put(index, digits, event.key);
			pos += (surplus === 1) ? 2 : 1;
		} else {
			Krbin.clearTmpInput();
		}
		update();
		binElem.setSelectionRange(pos, pos);
	});
	binElem.addEventListener('blur', (event) => {
		Krbin.clearTmpInput();
		update();
	});
	binElem.addEventListener('scroll', (event) => {
		rowNumberElem.scrollTop = event.target.scrollTop;
		strElem.scrollTop = event.target.scrollTop;
	});
	document.getElementById('download-button').addEventListener('click', (event) => {
		var elem = event.target;
		var blob = Krbin.exportToBlob();
		if (!blob) {
			event.preventDefault();
			return;
		}
		elem.href = window.URL.createObjectURL(blob);
		elem.download = Krbin.getSaveFileName();
	});

	function update() {
		var pos = binElem.selectionStart;
		rowNumberElem.innerHTML = Krbin.getRowNumberString();
		binElem.value = Krbin.getDataString();
		strElem.innerHTML = Krbin.getHTMLString();
		binElem.setSelectionRange(pos, pos);
	}
});

var Krbin = (function() {
	function Krbin() {}

	Krbin._filename;
	Krbin._data;
	Krbin._tmpInput;

	Krbin.init = function() {
		Krbin._filename = 'noname';
		Krbin._data = [];
		Krbin._tmpInput = '';
	};
	Krbin.loadByFile = function(file, onload) {
		Krbin._filename = file.name;
		var reader = new FileReader();
		reader.addEventListener('load', function(event) {
			Krbin._data = Array.prototype.slice.call(new Uint8Array(event.target.result));
			if (onload) {
				onload();
			}
		});
		reader.readAsArrayBuffer(file);
	};
	Krbin.loadByBinaryString = function(binStr) {
		binStr = binStr.replace(/\s/g, '');
		Krbin._data = binaryStringToArray(binStr);
	};
	Krbin.put = function(index, digits, value) {
		if (digits < 1 || 2 < digits) {
			return false;
		}
		value = parseInt(value, 16);
		if (Krbin._data[index] === undefined) {
			Krbin._tmpInput += value;
			if (digits === 1) {
				Krbin._data.push(parseInt(Krbin._tmpInput, 16));
				Krbin.clearTmpInput();
			}
		} else {
			Krbin.clearTmpInput();
			var orgValue = Krbin._data[index];
			var newValue = orgValue;
			if (digits === 1) {
				newValue = value + (orgValue & 0xf0);
			} else if (digits === 2) {
				newValue = (value * 16) + (orgValue & 0x0f);
			}
			Krbin._data[index] = newValue;
		}
	};
	Krbin.clearTmpInput = function() {
		Krbin._tmpInput = '';
	};
	Krbin.getRowNumberString = function() {
		var str = '';
		var num = 0;
		for (var i = 0, len = Krbin._data.length; i < len; ++i) {
			if ((i > 0 && i % 16 == 0) || i == len - 1) {
				str += padLineNumber(num.toString(16)) +'\n';
				num += 16;
			}
		}
		return str;
	};
	function padLineNumber(num) {
		var str = num + '';
		switch (str.length) {
			case 1: return '000'+ str;
			case 2: return '00'+ str;
			case 3: return '0'+ str;
			default: return str;
		}
	}
	Krbin.getDataString = function() {
		var str = '';
		for (var i = 0, len = Krbin._data.length; i <= len; ++i) {
			if (i > 0) {
				if (i % 16 == 0) {
					str += '\n';
				} else {
					str += ' ';
				}
			}
			if (i === len) {
				str += Krbin._tmpInput;
			} else {
				var charCode = Krbin._data[i];
				var hex = charCode.toString(16);
				str += padHex(hex);
			}
		}
		return str;
	};
	Krbin.getHTMLString = function() {
		var str = '';
		for (var i = 0, len = Krbin._data.length; i < len; ++i) {
			if (i > 0 && i % 16 == 0) {
				str += '\n';
			}
			var charCode = Krbin._data[i];
			str += isPrintable(charCode) ? escape(String.fromCharCode(charCode)) : '<span class="non-printable">.</span>';
		}
		return str;
	};
	function escape(c) {
		switch (c) {
			case '"': return '&#34;';
			case '&': return '&#38;';
			case "'": return '&#39;';
			case '<': return '&#60;';
			case '>': return '&#62;';
			default: return c;
		}
	}
	Krbin.exportToBlob = function() {
		if (Krbin._data.length <= 0) {
			return false;
		}
		return new Blob([new Uint8Array(Krbin._data)]);
	};
	Krbin.getSaveFileName = function() {
		return new Date().getTime() +'_'+ Krbin._filename;
	};
	function padHex(str) {
		switch (str.length) {
			case 0: return '00';
			case 1: return '0'+ str;
			case 2: return str;
			default: throw new Error('invalid hex string: '+ str);
		}
	}
	function binaryStringToArray(binStr) {
		var arr = [];
		var binStrArr = binStr.split('');
		var hex = '';
		for (var i = 0, len = binStrArr.length; i < len; ++i) {
			if (i > 0 && i % 2 === 0) {
				arr.push(parseInt(hex, 16));
				hex = '';
			}
			hex += binStrArr[i];
		}
		if (hex !== '') {
			arr.push(parseInt(padHex(hex), 16));
		}
		return arr;
	}
	function isPrintable(charCode) {
		return 0x20 <= charCode && charCode <= 0x7e;
	}

	return Krbin;
})();