/*
Copyright (c) 2010 Nathan Garabedian, All Rights Reserved.
Please contact me for permission to use this code (kttydoggy-a-t-yahoo-d-o-t-com)

Boot Sector Parsing Code 
Written in JavaScript by Nathan Garabedian

Version 0.1

Special thanks to those who have analyzed and made Sector 1 records available
on the Internet all over the place.  Here are a few places that I found invaluable
in creating this program:



*/
var dbg=true;
var params     = '';
var pbytes     = '';
var sectorType = 'unknown';
var bootCode   = [];
var bootSig    = [];
var bootParams = [];
var numColors=24;
var timer;
var codes=0;
var re='';
/*var colors = [
	'#ff9999','#ffbbee','#bbffff',
	'#bbbbff','#bbffbb','#ffbbbb',
	'#ddff99','#ffddff','#ccffff',
	'#ffdd99','#99ffdd','#ff99dd',
	'#cccc99','#99cccc','#cc99cc',
	'#9999cc','#99cc99','#cc9999',
	'#eeccaa','#aaeecc','#aaccee',
	'#eeaacc','#ccaaee','#cceeaa'
];*/
function d(x) {y=id('debug');y.innerHTML+="<br />"+x;}
function st(x) {id('status').innerHTML=x;}
function getXHR() {
	return XMLHttpRequest ? new XMLHttpRequest() :
		window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") :
		false;
}
String.prototype.trim = function() {
	return this.replace(/^\s+|\s+$/g,"");
}
String.prototype.ltrim = function() {
	return this.replace(/^\s+/,"");
}
String.prototype.rtrim = function() {
	return this.replace(/\s+$/,"");
}
function is_array(input){
    return typeof(input)=='object'&&(input instanceof Array);
}
function is_int(x) {
   var y=parseInt(x);
   if (isNaN(y)) return false;
   return x==y && x.toString()==y.toString();
} 
function md5(str) {
	return hex_md5(str);
}

function createXMLHttp() {
    if (typeof XMLHttpRequest != "undefined") {
        return new XMLHttpRequest();
    } else if (window.ActiveXObject) {
      var aVersions = [ "MSXML2.XMLHttp.5.0",
        "MSXML2.XMLHttp.4.0","MSXML2.XMLHttp.3.0",
        "MSXML2.XMLHttp","Microsoft.XMLHttp"
      ];

      for (var i = 0; i < aVersions.length; i++) {
        try {
            var oXmlHttp = new ActiveXObject(aVersions[i]);
            return oXmlHttp;
        } catch (oError) {
            //Do nothing
        }
      }
    }
    throw new Error("XMLHttp object could be created.");
}
 
window.onload=init;
function init() {
	initParameters();
	selectChanged();
	if( dbg==false ) {
		id('debug').style.display='none';
	}
}

function id(x){return document.getElementById(x);}
function selectChanged() {
	updatePage();
}
function buttonPressed() {
	updatePage();
}

function updatePage() {
	var v = id('pbytes');
	var r = id('params');
	var d = id('txtdata');
	var s = id('status');
	var sel = id('select');

	if( sel.selectedIndex == -1 ) sel.selectedIndex = 0;
	id('txtdata').innerHTML = sel.options[sel.selectedIndex].value;
	s.innerHTML = '';
	
	if( d.value.trim() != '' ) {
		parseBootCode(d.value.replace(/\n/gi,' '));
		r.innerHTML = params;
		v.innerHTML = pbytes;
		v.style.visibility="visible";
		r.style.visibility="visible";
	} else {
		v.style.visibility="hidden";
		r.style.visibility="hidden";
	}
}

function parseBootCode(bc) {
	bootCode = [];
	// split string into array with third character as the delimiter
	// i.e. "55 AA XX" becomes Array("55","AA","XX")
	bootCode = bc.toUpperCase().trim().split(bc.charAt(2));
  
	// Truncate boot sectors to 512 bytes
	if( bootCode.length != 512 ) {
		//bootCode = bootCode.slice(0,512);
	}

	bootSigSieve();
	
	readBytesAndParameters();
	//params = outputBytes();
	//pbytes = outputParameters();
}

function readBytesAndParameters() {
	params = ''; // parameters
	pbytes = ''; // bytes of sector
	var calcVal;

	params += '<table><tr><td>Boot Sector Match:&nbsp;'+
		'</td><td><span style="color:#dd0000">'+
		sectorType + "</color></td></tr>\n";
	
	var bps = bootParams[sectorType];
	var marked = [];
	var colorIndex=1;
	for( var bp in bps ) {
		// mark fielded bytes as a specific color in marked array
		for( var i=0; i<bps[bp][1]; i++ ) {
			marked[bps[bp][0]+i] = colorIndex;
		}
		
		// write out paramters in same colors
		// constructParam(index,length,string,color)
		var str = bps[bp][3];
		var val = bps[bp][2];
				
		if( bps[bp][2] && bps[bp][2] != '' && !is_array(bps[bp][2])) {
			val = bps[bp][2] + "&nbsp;("+getValue(bootCode,bps[bp][0],bps[bp][1],bps[bp][4])+")";
			params +=getParamString(str,val,colorIndex%numColors);
		} else if( is_array(bps[bp][2])) {
			str = "";
			for( var ba in bps[bp][2] ) {
				var bx = bps[bp][2][ba];
				str = bx[3].replace(/\$/gi,bps[bp][3]);
				calcVal = getValue(bootCode,bx[0]+bps[bp][0],bx[1],bx[4]);
				if( !bx[4] && !bx[5] ) {
					val = calcVal;
				} else {
					if( bx[4]==true && !bx[5] ) {
						val = getValue(bootCode,bx[0]+bps[bp][0],bx[1],bx[4]);
					} else if( bx[5] && bx[5] != '' ) {
						val = eval(bx[5]+"('"+calcVal+"')");
					} else {
						val = "&nbsp;(0x"+calcVal+")\n";
					}
				}
				
				params +=getParamString(str,val,colorIndex%numColors);	
			}
			
		} else {
			calcVal = getValue(bootCode,bps[bp][0],bps[bp][1],bps[bp][4]);
			if( !bps[bp][4] && !bps[bp][5] ) {
				val = calcVal;
			} else {
				if( bps[bp][4]==true && !bps[bp][5] ) {
					val = getValue(bootCode,bps[bp][0],bps[bp][1],bps[bp][4]);
				} else if( bps[bp][5] && bps[bp][5] != '' ) {
					val = eval(bps[bp][5]+"('"+calcVal+"')");
				} else {
					val = "&nbsp;(0x"+calcVal+")\n";
				}
			}
			params +=getParamString(str,val,colorIndex%numColors);
		}
		colorIndex++;
	}
	params += "</table>\n";
	
	// set background color based on marked number
	// column heading
	var heading = '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0' +
		'&nbsp;&nbsp;1&nbsp;&nbsp;2&nbsp;&nbsp;3&nbsp;&nbsp;4' +
		'&nbsp;&nbsp;5&nbsp;&nbsp;6&nbsp;&nbsp;7&nbsp;&nbsp;8' +
		'&nbsp;&nbsp;9&nbsp;&nbsp;A&nbsp;&nbsp;B&nbsp;&nbsp;C' +
		'&nbsp;&nbsp;D&nbsp;&nbsp;E&nbsp;&nbsp;F';
	for( var i=0; i<bootCode.length; i++ ) {
		if( i % 512 == 0 )
			pbytes += heading + "&nbsp;&nbsp;SECTOR "+
				(Math.floor(i/512)+1) + "<br />\n";
		if( i % 16 == 0) {
			var y = i/16;
			// write hex chars with leading zeros
			pbytes +='0x'+(y>0xFFFF ? 
				(y<0x100?'0':'')+(y<0x10?'0':'')+
				(y<0x1000?'0':'')+(y<0x10000?'0':'')+
				(y<0x100000?'0':'')+(y<0x1000000?'0':'')
				:
				(y<0x100?'0':'')+(y<0x10?'0':'')
				)+
				y.toString(16).toUpperCase()+'0:';
		}
		if( marked[i]!=undefined ) {
			pbytes += '<span class="c' + 
				marked[i]%numColors +
				'">' + bootCode[i];
			if( marked[i] == marked[i+1] ) {pbytes += '&nbsp;';}
			pbytes += '</span>';
			if( marked[i] != marked[i+1] ) {pbytes += '&nbsp;';}
		} else {
			pbytes += bootCode[i] + '&nbsp;';
		}
		if( i % 16 == 15 ) {
			for( var j = 15; j>=0; j-- ) {
				var bcInt = parseInt(bootCode[i-j],16);
				var chars = '';
				
				if( bcInt==0x20 ) 
					chars += '&nbsp;';
				else if( bcInt > 0x20 && bcInt < 0x7F || bcInt > 0x9F )	
					chars += String.fromCharCode(bcInt);
				else
					chars += '.';

				pbytes += chars;
				if( j%16==8 ) pbytes += '&nbsp;';
			}
			pbytes += '<br />\n';
		}
	}	
	pbytes += heading + "<br />\n";
}

// base, offset, replace$, array
function getParamArray( arr ) {
	var retarr = [];
	for( var a in arr ) {
		if( a && is_array(a) && is_array(a[3])) {
			for( var y in arr ) {
				x=getParamArray(y)
				if( x && is_array(x) && is_int(x[0])) {
					retarr.push(x);
				}
			}
		} else if( a && is_array(a) && is_int(a[0])) {
			a[3] = a[3].replace(/\$/gi,a[1])
			a[0] = a[0] + arr[0];
			retarr.push(a);
		}
	}
	return retarr;
}

// constructParam(string,value,color)
function getParamString( str, val, c ) {	
	return (
		'<tr>'+
		'<td>'+
		'<span class="c'+c+'">'+
		str+':&nbsp;'+
		'</span>'+
		'</td>'+	
		'<td><span class="c'+c+'">'+
		val+
		"</span></td></tr>\n");
}

function getValue( arr, i, len, bigEndian ) {
	var retval = '';
	if( bigEndian == true ) {
		for( var j = i; j<i+len; j++ )
			retval += arr[j] + (j==i+len-1? "":" ");
	} else {
		for( var j = i+len-1; j>=i; j-- )
			retval += arr[j] + (j==i?"":" ");
	}
	return retval;
}

function bootSigSieve() {
	var matched;
	for( var i in bootSig ) {
	  matched = true;
	  
	  // iterate through boot patterns in bootSig
	  for( var j in bootSig[i] ) {
		if( !match(bootCode,bootSig[i][j])) {
		  matched = false;
		  break; // break on an unmatched entry
		}
	  }
	  // we've survived the loop and matched stayed true
	  if( matched==true ) {
		// the key in bootSig is our answer
		sectorType = i;
		break;
	  }
	}
	// we exhausted our match possibilities.  No match found
	if( matched==false ) {
		sectorType = 'UNKNOWN';
//		status += "Match not found.<br />\n";
	} else { // we matched a sectorType
//		status += "Found a match! " + sectorType + "<br />\n";
	}
}

function match( arr, matchStrArr ) {
	// arr is the byte array of the boot sector
	// matchStrArr consists of:
	// [0] position of first byte in string
	// [1] string to match
	// or an array for either to represent 'one of' them
	var sa='';
	var i=0;
	if( is_array(matchStrArr[0])) {
		sa = matchStrArr[1].toUpperCase().trim().split(matchStrArr[1].charAt(2));
		for( var x in matchStrArr[0] ) {
			i = matchStrArr[0][x];
			var retval=true;
			for( var j=0; j<sa.length; j++ ) {
				if( arr[j+i] != sa[j] ) 
					retval = false;
			}
			if( retval==true ) return true;
		}
		return false;
	} else if( is_array(matchStrArr[1])) {
		i = matchStrArr[0];
		for( var x in matchStrArr[1] ) {
			sa = matchStrArr[1][x].toUpperCase().trim().split(matchStrArr[1][x].charAt(2));
			var retval=true;
			for( var j=0; j<sa.length; j++ ) {
				if( arr[j+i] != sa[j] ) 
					retval = false;
			}
			if( retval==true ) return true;
		}
		return false;
	} else {
		sa = matchStrArr[1].toUpperCase().trim().split(matchStrArr[1].charAt(2));
		i = matchStrArr[0]; // index of first byte
		for( var j=0; j<sa.length; j++ ) {
			if( arr[j+i] != sa[j] ) return false;
		}
		return true;
	}
	return false;
}

function active(x) {
  if( x=='80' ) return 'Yes (0x' + x + ')';
  return 'No (0x' + x + ')';
}

function MBRPartType(pt) {
 	// Parameters for Partition Type
	// 00h is unknown or nothing
	// 01h - 12-bit FAT
	// 04h - 16-bit FAT
	// 05h - Extended MS-DOS Partition
	// 06h - 16-bit FAT (Larger than 32MB)
	// 0Bh - 32-bit FAT (Up to 2048GB)
	// 0Ch - Same as 0Bh with LBA 13h Extensions
	// 0Eh - Same as 06h with LBA 13h Extensions
	// 0Fh - Same as 05h with LBA 13h Extensions
	// help from http://www.win.tue.nl/~aeb/partitions/partition_types-1.html
  var retval = '(' + pt + ')';
  if(      pt=='00' ) return retval +'Empty';
  else if( pt=='01' ) return retval +'DOS 12-bit FAT';
  else if( pt=='02' ) return retval +'XENIX root';
  else if( pt=='03' ) return retval +'XENIX /usr';
  else if( pt=='04' ) return retval +'DOS 3.0+ 16-bit FAT';
  else if( pt=='05' ) return retval +'DOS 3.3+ Extended Partition';
  else if( pt=='06' ) return retval +'DOS 3.31 16-bit FAT (Larger than 32MB)';
  else if( pt=='07' ) return retval +'OS/2 IFS/NTFS (Win NT 3.1)/exFAT(FAT64)';
  else if( pt=='08' ) return retval +
	'OS/2 1.0-1.3/AIX Boot partition/<br />SplitDrive/Commodore DOS/Dell Span/QNX 1-2';
  else if( pt=='09' ) return retval +'AIX data partition/Coherent filesystem/QNX 1-2';
  else if( pt=='0A' ) return retval +'OS/2 Boot Manager/Coherent Swap/OPUS';
  else if( pt=='0B' ) return retval +
	'Win95 OSR2 FAT32';  //0b, 0c, 0e, 0f not supported by WinNT; 0e,0f analog to 05,06
  else if( pt=='0C' ) return retval +'Win95 OSR2 FAT32, LBA-mapped';
  else if( pt=='0E' ) return retval +'Win95: DOS 16-bit FAT, LBA-mapped';
  else if( pt=='0F' ) return retval +'Win95 Extended Partition, LBA-mapped';
  else if( pt=='10' ) return retval +'OPUS';
  else if( pt=='11' ) return retval +
	'Hidden DOS 12-bit FAT <br />(OS/2: 01,04,06,07 => 11,14,16,17)';
  else if( pt=='12' ) return retval +
	'Configuration/diagnostics (Compaq,Intel,etc)';
  else if( pt=='14' ) return retval +
	'Hidden DOS 16-bit FAT <br />(OS/2: 01,04,06,07 => 11,14,16,17)/AST MS-DOS Extended';
  else if( pt=='16' ) return retval +
	'Hidden DOS 16-bit FAT >=32MB<br />(OS/2: 01,04,06,07 => 11,14,16,17)';
  else if( pt=='17' ) return retval +
	'Hidden IFS<br />(OS/2: 01,04,06,07 => 11,14,16,17)';

    
  else if( pt=='0B' ) return retval +'32-bit FAT (Up to 2048GB)';
  else if( pt=='0C' ) return retval +'32-bit FAT with LBA 13h Extensions';
  else if( pt=='0E' ) return retval +'16-bit FAT with LBA 13h Extensions';
  else if( pt=='0F' ) return retval +'Extended MS-DOS Partition with LBA 13h Extensions';
  else if( pt=='82' ) return retval +'Linux Swap Partition';
  else if( pt=='83' ) return retval +'Linux ext2 Partition';
  else return retval +'UNKNOWN VALUE';
}
function mediaDescriptor(md) {
	// ref http://stanislavs.org/helppc/media_descriptor_byte.html
	// ref http://support.microsoft.com/kb/140418
	var retval='';
	if( md=='00' ) retval += 'UNKNOWN';
	else if( md=='F0' ) retval +='1.44MB or 2.88MB 3.5" DS,HD';
	else if( md=='F8' ) retval +='Hard Drive';
	else if( md=='F9' ) retval +='1.2MB 5.25" DS,HD or 720KB 3.5" DS,DD';
	else if( md=='FA' ) retval +='RAM disk';
	else if( md=='FC' ) retval +='5.25" SS,DD or 8" DS,SD';
	else if( md=='FD' ) retval +='360k 5.25" DS,DD';
	else if( md=='FE' ) retval +='5.25" SS,DD or 8" SS,SD';
	else if( md=='FF' ) retval +='320k 5.25" DS,DD';
	else retval += 'UNKNOWN VALUE';
	return retval + '(0x' + md + ')';
}

function decimal(hx) {
	hexNum = '0x'+hx.replace(/ /gi,'');
	
	return hexNum + " (" + parseInt(hexNum,16) + ")";
}

// prints out all the zero-terminated strings on separate lines in hideable box
// if last char is not '00' prints out the end quote to finish off the string
function strings(pt) {
	var retval = '"';
	var sa = pt.toUpperCase().trim().split(pt.charAt(2)); 
	for( var j = 0; j<sa.length; j++ ) {
		var bcInt = parseInt(sa[j],16);
		var chars = '';
		
		if( bcInt==0x20 ) 
			chars += '&nbsp;';
		else if(bcInt==0)
			chars += j<sa.length-1?'"<br />"':'';
		else if( bcInt > 0x20 && bcInt < 0x7F || bcInt > 0x9F )	
			chars += String.fromCharCode(bcInt);
		else
			chars += '.';

		retval += chars;
	}
	retval +='"';
	if( sa.length > 8 )
		retval = 
		'<span class="lnk" onclick="show(\'' + md5(retval) + 
		'\')">show/hide strings...'+
		'</span><br />' +
		'<span style="display:none;" id="' + md5(retval) + '">' + 
		retval + "</span>\n";

	return retval;
}

function truncate(pt) {
	var sa = pt.toUpperCase().trim().split(pt.charAt(2)); 
	var hiddentext = '';
	var retval='';
	if( sa.length > 8 ) {
		for( var j = 0; j<sa.length; j++ ) {
			hiddentext += sa[j] + "&nbsp;";
			if( j%8==7 ) hiddentext += '<br />';
		}
		retval = 
		'<span class="lnk" onclick="show(\'' + md5(pt) + '\')">'+
		sa[0]+' '+sa[1]+' '+sa[2]+' '+sa[3]+' '+'...'+
		'</span><br />' +
		'<span style="display:none;" id="' + md5(pt) + '">' + 
		hiddentext + "</span>\n";
	} else retval = pt;
	return retval;
}


function animatemsg(dest) {
	el = document.getElementById(dest);
	if( el.innerHTML == 'Disassembling...' ) 
		el.innerHTML = 'Disassembling';
	else 
		el.innerHTML += ".";
	
	timer = setTimeout("animatemsg('" + dest +"')",300);
}

function code(c) {
	st("Disassembling...");
	if(!timer) { animatemsg('status'); }
	
	// xmlhttprequest object
	var xh = getXHR();
	re = '';
	if( xh ) {
/*		xh.onreadystatechange = function () {
			if ((xh.readyState == "4" || 
				xh.readyState == "complete") && 
				(xh.status == "200" || xh.status == "OK")) 
			{	
				
				st("Code Disassembled");
				var cstr = xh.responseText;
				re = '<span class="lnk" onclick="show(\'' + md5(cstr) + 
					'\')">show/hide code</span>' + 
					'<span style="display:none;" id="' + md5(cstr) + '">' + 
					cstr + "</span>\n";
			}
		};
*/
		xh.open("GET","getop.php?b="+c.replace(/ /gi,'%20'),false);
		xh.send("");
	}
	st("Code Disassembled");
	setTimeout('st("")',1500);
	var cstr = xh.responseText;
	re = '<span class="lnk" onclick="show(\'' + md5(cstr) + 
		'\')">show/hide code</span>' + 
		'<span style="display:none;" id="' + md5(cstr) + '">' + 
		cstr + "</span>\n";
	clearTimeout(timer);
	return re;
}


function show(idstr) {
	var x = id(idstr).style;
	if( x.display == "none" ) x.display = "";
	else x.display = "none";
	return;
}

function findByteIndex(str) {
	var bps = bootParams[sectorType];

	for( var bp in bps ) {
		for( var i=0; i<bps[bp][1]; i++ ) {
			if( !is_int(bps[bp][0]) ) {
				
			}
		}
	}
}

function initParameters() {
	// boot sigature strings that can be used in the below bootSig array
	var winXPBootCode = [0x00,
		"33 C0 8E D0 BC 00 7C 8E C0 8E D8 BE 00 7C BF 00"
	];

	var ibmDosBootCode = [0x00,
		"FA 33 C0 8E D0 BC 00 7C 8B F4 50 07 50 1F FB FC " +
		"BF 00 06 B9 00 01"
	];
/*						  "F3 A5 EA 1D 06 00 00 BE BE 07 " +
		"B3 04 80 3C 80 74 0E 82 3C 00 75 1C 83 C6 10 FE " +
		"CB 75 EF CD 18 8B 14 8B 4C 02 8B EE 83 C6 10 FE " +
		"CB 74 1B 82 3C 00 74 F4 BE 8B 06 32 ED AC 8A C8 " +
		"AC 56 BB 07 00 B4 0E CD 10 5E E2 F4 EB FE BF 05 " + 
		"00 BB 00 7C B8 01 02 57 CD 13 5F 73 0C 33 C0 CD " +
		"13 4F 75 ED BE A3 06 EB D2 BE C2 06 81 3E FE 7D " +
		"55 AA 75 C7 8B F5 EA 00 7C 00 00 "];
*/
	var ibmDosBootStrings = [0x8B,"17 49 6E 76 61" +
		"6C 69 64 20 70 61 72 74 69 74 69 6F 6E 20 74 61 " +
		"62 6C 65 1E 45 72 72 6F 72 20 6C 6F 61 64 69 6E " +
		"67 20 6F 70 65 72 61 74 69 6E 67 20 73 79 73 74 " +
		"65 6D 18 4D 69 73 73 69 6E 67 20 6F 70 65 72 61 " +
		"74 69 6E 67 20 73 79 73 74 65 6D "];
	var ibmDosAuthor = [0xDB,"41 75 74 68 6F " + 
		"72 20 2D 20 44 61 76 69 64 20 4C 69 74 74 6F 6E "];
	var ntfsZero1   = [0x10,"00"];
	var ntfsZero2   = [0x11,"00 00"];
	var tnfsZero3   = [0x16,"00 00"];
	var ntfsBootSig = [3,"4E 54 46 53 20 20 20 20"];
	var hfsPlusSig  = [0,"48 2B 00 04"];
	var hfsXSig     = [0,"48 58 00 05"];
	var gptBootmgr  = [0x02,'42 00 4F 00 4F 00 54 00 4D 00 47 00 52 00'];
	var fatMediaDescriptorFloppy = [
		0x15,["F0 ","F9 ","FA ","FB ","FC ","FD ","FE ","FF "]
	];
	var fatMediaDescriptorHDD = [0x15,"F9"];
	var grubJmp = [0x00,"EB 48 90"];
	var grubSig = [[0x176,0x179,0x17B],"47 52 55 42 20"];
	var liloOemId = [0x06,"4C 49 4C 4F"];
	var mbrPatternMagicNumber = [510,"55 AA"];

	// Program will try to match one of the array elements listed if there are more than one
	
	// This is like an inverted tree.  Most specific items first, then more generic items last.
	bootSig['DOSMBR'] = [
		mbrPatternMagicNumber,
		ibmDosBootCode
	];
	bootSig['WINMBR'] = [
		mbrPatternMagicNumber,
		winXPBootCode
	];

	bootSig['FAT16floppy'] = [
		mbrPatternMagicNumber,
		fatMediaDescriptorFloppy
	];
	bootSig['FAT16hdd'] = [
		mbrPatternMagicNumber,
		fatMediaDescriptorHDD
	];
	bootSig['NTFS'] = [
		mbrPatternMagicNumber,
		ntfsBootSig
	];
	
	// http://www.digitalforensics.ch/nikkel09.pdf
	bootSig['GPT'] = [
		gptBootmgr
	];
	bootSig['HFS+'] = [
		hfsPlusSig
	];
	bootSig['HFSX'] = [
		hfsXSig
	];
	bootSig['LILO'] = [
		liloOemId,
		mbrPatternMagicNumber
	];
	bootSig['GRUB'] = [
		grubJmp,
		grubSig,
		mbrPatternMagicNumber
	];
	bootSig['MBR'] = [
		mbrPatternMagicNumber
	];
	

	// boot data structures
	
	
	//offset, length, , name
	mbrPartStructure = [
		[0,1,,'Partition $ Active',,'active'],
		[1,1,,'Beginning&nbsp;Head',,'decimal'],
		[2,2,,'Beginning&nbsp;Cyl',,'decimal'],
		[4,1,,'Partition&nbsp;Type',,'MBRPartType'],
		[5,1,,'End&nbsp;Head',,'decimal'],
		[6,2,,'End&nbsp;Cyl',,'decimal'],
		[8,2,,'Sectors between MBR and P$',,'decimal'],
		[10,4,,'Total Sectors in P$',,'decimal']
	];
	
	
	
	// GUID Partition Table (Windows Vista, 7, 2008; Intel-based Macs)
	// specification at http://www.intel.com/technology/efi/
	bootParams['GPT'] = [
		[0x02,14,,'Partition&nbsp;Type',true]
	];
	bootParams['GRUB'] = [
		[0x00,3,,'JMP Instruction[EB 48 90]',true,'code'],
		[0x03,0x3B,,'BPB-Not used by GRUB',true,'truncate'],
		[0x3E,0xC,,'GRUB data',true],
		[0x4A,0x12F,,'GRUB instructions1',true,'code'],
		[0x179,6,,'Signature',true,'strings'],
		[0x17F,0x1B,,'Strings',true,'strings'],
		[0x19A,13,,'GRUB display sub.',true,'code'],
		[0x1B8,4,,'Not used by GRUB (NTFS Ser#)',true],
		[0x01BE,0x10,mbrPartStructure,'1'],
		[0x01CE,0x10,mbrPartStructure,'2'],
		[0x01DE,0x10,mbrPartStructure,'3'],
		[0x01EE,0x10,mbrPartStructure,'4'],
		[0x01fe,2,,'Magic Number',true]
	];

	bootParams['LILO'] = [
		[0x00,3,,'CLI and JMP [FA EB 6C]',true,'code'],
		[0x03,3,,'lba (optional)',true,'strings'],
		[0x06,4,,'LILO string',true,'strings'],
		[0x0C,2,,'LILO version',,'decimal'],
		[0x0E,2,,'Input Timeout',,'decimal'],
		[0x10,2,,'Boot Delay',,'decimal'],
		[0x12,1,,'COM port used',,'decimal'],
		[0x13,1,,'Serial Port Parameters',,'decimal'],
		[0x14,4,,'Timestamp'],
		[0x18,2,,'First Descriptor Sector Addr (CX)',,'decimal'],
		[0x1A,2,,'First Descriptor Sector Addr (DX)',,'decimal'],
		[0x1C,1,,'not used'],
		[0x1D,2,,'Second Descriptor Sector Addr (CX)',,'decimal'],
		[0x1F,2,,'Second Descriptor Sector Addr (DX)',,'decimal'],
		[0x21,1,,'not used'],
		[0x22,2,,'Default Command-Line Sector Addr (CX)',,'decimal'],
		[0x24,2,,'Default Command-Line Sector Addr (DX)',,'decimal'],
		[0x26,1,,'not used'],
		[0x27,1,,'Prompt always entered?'],
		[0x28,2,,'Greeting Msg Length',,'decimal'],
		[0x2A,2,,'Location of Message (CX)',,'decimal'],
		[0x2C,2,,'Location of Message (DX)',,'decimal'],
		[0x2E,1,,'not used'],
		[0x2F,2,,'Keyboard Transl Table Loc (CX)',,'decimal'],
		[0x31,2,,'Keyboard Transl Table Loc (DX)',,'decimal'],
		[0x2E,1,,'kt_AL'],
		[0x34,40,,'Second Stage Sector Addresses',,'truncate'],
		[0x5c,4,,'????'],
		[0x6a,5,,'For copying ext data'],
		[0x6F,0x29,,'LILO Boot Code1',true,'code'],
		[0x98,0x54,,'LILO Boot Code2',true,'code'],
		[0x01BE,0x10,mbrPartStructure,'1'],
		[0x01CE,0x10,mbrPartStructure,'2'],
		[0x01DE,0x10,mbrPartStructure,'3'],
		[0x01EE,0x10,mbrPartStructure,'4'],
		[0x01fe,2,,'Magic Number',true]
	];
	
	bootParams['WINMBR'] = [
		[0x00,0x163,,'MBR boot code',true,'code'],
		[0x163,0x52,,'Strings',true,'truncate'],
		[0x1B5,3,,'String Offsets',true],
		[0x1B8,4,,'Signature',true],
		[0x01BE,0x10,mbrPartStructure,'1'],
		[0x01CE,0x10,mbrPartStructure,'2'],
		[0x01DE,0x10,mbrPartStructure,'3'],
		[0x01EE,0x10,mbrPartStructure,'4'],
		[0x01fe,2,,'Magic Number',true]
	];

	bootParams['DOSMBR'] = [
		[0x00,0x8B,,'MBR Boot Code',true,'code'],
		[0x8B,0x50,,'MBR Boot Strings',true,'strings'],
		[0xDB,0xE3,,'Zeros',true,'truncate'],/*ng*/
		[0x01BE,0x10,mbrPartStructure,'1'],
		[0x01CE,0x10,mbrPartStructure,'2'],
		[0x01DE,0x10,mbrPartStructure,'3'],
		[0x01EE,0x10,mbrPartStructure,'4'],
		[0x01fe,2,,'Magic Number',true]

	];

	bootParams['MBR'] = [
		[0x00,446,,'MBR boot code',true,'code'],
		[0x01BE,0x10,mbrPartStructure,'1'],
		[0x01CE,0x10,mbrPartStructure,'2'],
		[0x01DE,0x10,mbrPartStructure,'3'],
		[0x01EE,0x10,mbrPartStructure,'4'],
		[0x01fe,2,,'Magic Number',true]

	];
	
	bootParams['NTFS'] = [
		// ref http://bootmaster.filerecovery.biz/appnote3.html
		// position, length, value, name, bigEndian, color
		[0x00,3,,'JMP Instruction[EB 52 90]',true,'code'],
		[0x03,8,'','OEM ID ("NTFS&nbsp;&nbsp;&nbsp;&nbsp;")',true,'strings'],
		//[0x0B,25,'','BIOS Parameter Block (BPB)',true],
		[0x0B,2,,'Sector Size in Bytes(512)[02 00]',,'decimal'],
		[0x0D,1,,'Sectors per Cluster (1,2,4,8)',,'decimal'],
		/*
		  	" Number of sectors per allocation unit. This value must be a power of 2
			that is greater than 0. parameters of 1, 2, 4, 8 are quite common."
			I've seen a value of 4 ( for a Windows XP partition of less than 2GB ), 
			but a value of 8 ( for Windows 2000 and XP ) is probably the most common.
		*/
		[0x0E,2,,'Reserved Sectors [00 00]'],
		/*
			After loading into Memory, this location becomes: 7C0Eh, and it's used to 
			store how many sectors of the Boot Record are to be read into Memory;
			it begins with a value of 16 (decimal) and counts down to zero. 
			(See line: 7C6C below.)
		*/
		[0x10,3,,'Must be Zero[00 00 00]'],
		[0x13,2,,'Not used by NTFS[00 00 00 00]'],
		[0x15,1,,'Media Descriptor',,'mediaDescriptor'], // not used by Win2k/XP
		[0x16,2,,'Must be Zero[00 00]'],
		[0x18,2,,'Sectors per Track(63)[00 3F]',,'decimal'],
		[0x1A,2,,'Number of Heads',,'decimal'],
		[0x1C,4,,'Number of Hidden Sectors 0x0000003F(63)'+
			'<br /> for XP or 0x00000800(2048) for Vista/7',,'decimal'],
		[0x20,4,,'Not used by NTFS, usually 0'],
		/* 
			After loading into Memory ( and carrying out the instructions in the 
			subroutine at offsets 7C7B and following ), offset 7C20h is used to store 
			the Total Number of Sectors in the partition we're trying to boot ; 
			see line: 7CA5 for the reference.
		*/
		[0x24,4,,'First byte is drive number [80008000]',true],
		[0x28,8,,'Total Sectors -1',,'decimal'],
		[0x30,8,,'Starting Cluster of $MFT',,'decimal'],
		[0x38,8,,'Starting Cluster of $MFTMirror',,'decimal'],
		[0x40,4,,'Clusters per File Record Segment*',,'decimal'],
		[0x44,4,,'Clusters per Index Block (1)',,'decimal'],
		[0x48,8,,'NTFS Serial Number',true],
		[0x50,4,,'Checksum (0)',true],
		[0x54,426,,'Bootstrap Code',true,'code'],
		[0x01fe,2,,'Magic Number',true]
	];

	// Original IBM DOS 2.0 MBR
	bootParams['IBMDOS20'] = [
		[0x00,138,,'Boot Code',true,'code'],
		[0x8B,80,,'Boot Strings',true,'strings'],
		[0xDB,21,,'Author',true,'strings'],
		[0x01FE,2,,'Magic Number',true]
	];
	
	bootParams['FAT16hdd'] = [
		[0x00,3,,'JMP Instruction[EB 52 90]',true,'code'],
		[0x03,8,'','OEM ID',true,'strings'],
		[0x15,1,'','Media Descriptor[F9]',true,'mediaDescriptor'],
		[0x54,426,,'Bootstrap Code',true],
		[0x01BE,0x10,mbrPartStructure,'1'],
		[0x01CE,0x10,mbrPartStructure,'2'],
		[0x01DE,0x10,mbrPartStructure,'3'],
		[0x01EE,0x10,mbrPartStructure,'4'],
		[0x01FE,2,,'Magic Number',true]
	];
	
	bootParams['UNKNOWN'] = bootParams['FAT16'];
	bootParams['FAT16floppy'] = bootParams['FAT16'];
}
