//display-name: "exe-DOS"

LZ90Signature: [
	0x06, 0x0E, 0x1F, 0x8B, 0x0E, 0x0C, 0x00, 0x8B,
    0xF1, 0x4E, 0x89, 0xF7, 0x8C, 0xDB, 0x03, 0x1E,
    0x0A, 0x00, 0x8E, 0xC3, 0xB4, 0x00, 0x31, 0xED,
    0xFD, 0xAC, 0x01, 0xC5, 0xAA, 0xE2, 0xFA, 0x8B,
    0x16, 0x0E, 0x00, 0x8A, 0xC2, 0x29, 0xC5, 0x8A,
    0xC6, 0x29, 0xC5, 0x39, 0xD5, 0x74, 0x0C, 0xBA,
    0x91, 0x01, 0xB4, 0x09, 0xCD, 0x21, 0xB8, 0xFF,
    0x4C, 0xCD, 0x21, 0x53, 0xB8, 0x53, 0x00, 0x50,
    0xCB, 0x2E, 0x8B, 0x2E, 0x08, 0x00, 0x8C, 0xDA,
    0x89, 0xE8, 0x3D, 0x00, 0x10, 0x76, 0x03, 0xB8,
    0x00, 0x10, 0x29, 0xC5, 0x29, 0xC2, 0x29, 0xC3,
    0x8E, 0xDA, 0x8E, 0xC3, 0xB1, 0x03, 0xD3, 0xE0,
    0x89, 0xC1, 0xD1, 0xE0, 0x48, 0x48, 0x8B, 0xF0,
    0x8B, 0xF8, 0xF3, 0xA5, 0x09, 0xED, 0x75, 0xD8,
    0xFC, 0x8E, 0xC2, 0x8E, 0xDB, 0x31, 0xF6, 0x31,
    0xFF, 0xBA, 0x10, 0x00, 0xAD, 0x89, 0xC5, 0xD1,
    0xED, 0x4A, 0x75, 0x05, 0xAD, 0x89, 0xC5, 0xB2,
    0x10, 0x73, 0x03, 0xA4, 0xEB, 0xF1, 0x31, 0xC9,
    0xD1, 0xED, 0x4A, 0x75, 0x05, 0xAD, 0x89, 0xC5,
    0xB2, 0x10, 0x72, 0x22, 0xD1, 0xED, 0x4A, 0x75,
    0x05, 0xAD, 0x89, 0xC5, 0xB2, 0x10, 0xD1, 0xD1,
    0xD1, 0xED, 0x4A, 0x75, 0x05, 0xAD, 0x89, 0xC5,
    0xB2, 0x10, 0xD1, 0xD1, 0x41, 0x41, 0xAC, 0xB7,
    0xFF, 0x8A, 0xD8, 0xE9, 0x13, 0x00, 0xAD, 0x8B,
    0xD8, 0xB1, 0x03, 0xD2, 0xEF, 0x80, 0xCF, 0xE0,
    0x80, 0xE4, 0x07, 0x74, 0x0C, 0x88, 0xE1, 0x41,
    0x41, 0x26, 0x8A, 0x01, 0xAA, 0xE2, 0xFA, 0xEB,
    0xA6, 0xAC, 0x08, 0xC0, 0x74, 0x40, 0x3C, 0x01,
    0x74, 0x05, 0x88, 0xC1, 0x41, 0xEB, 0xEA, 0x89
]

LZ91Signature: [
	0x06, 0x0E, 0x1F, 0x8B, 0x0E, 0x0C, 0x00, 0x8B,
    0xF1, 0x4E, 0x89, 0xF7, 0x8C, 0xDB, 0x03, 0x1E,
    0x0A, 0x00, 0x8E, 0xC3, 0xFD, 0xF3, 0xA4, 0x53,
    0xB8, 0x2B, 0x00, 0x50, 0xCB, 0x2E, 0x8B, 0x2E,
    0x08, 0x00, 0x8C, 0xDA, 0x89, 0xE8, 0x3D, 0x00,
    0x10, 0x76, 0x03, 0xB8, 0x00, 0x10, 0x29, 0xC5,
    0x29, 0xC2, 0x29, 0xC3, 0x8E, 0xDA, 0x8E, 0xC3,
    0xB1, 0x03, 0xD3, 0xE0, 0x89, 0xC1, 0xD1, 0xE0,
    0x48, 0x48, 0x8B, 0xF0, 0x8B, 0xF8, 0xF3, 0xA5,
    0x09, 0xED, 0x75, 0xD8, 0xFC, 0x8E, 0xC2, 0x8E,
    0xDB, 0x31, 0xF6, 0x31, 0xFF, 0xBA, 0x10, 0x00,
    0xAD, 0x89, 0xC5, 0xD1, 0xED, 0x4A, 0x75, 0x05,
    0xAD, 0x89, 0xC5, 0xB2, 0x10, 0x73, 0x03, 0xA4,
    0xEB, 0xF1, 0x31, 0xC9, 0xD1, 0xED, 0x4A, 0x75,
    0x05, 0xAD, 0x89, 0xC5, 0xB2, 0x10, 0x72, 0x22,
    0xD1, 0xED, 0x4A, 0x75, 0x05, 0xAD, 0x89, 0xC5,
    0xB2, 0x10, 0xD1, 0xD1, 0xD1, 0xED, 0x4A, 0x75,
    0x05, 0xAD, 0x89, 0xC5, 0xB2, 0x10, 0xD1, 0xD1,
    0x41, 0x41, 0xAC, 0xB7, 0xFF, 0x8A, 0xD8, 0xE9,
    0x13, 0x00, 0xAD, 0x8B, 0xD8, 0xB1, 0x03, 0xD2,
    0xEF, 0x80, 0xCF, 0xE0, 0x80, 0xE4, 0x07, 0x74,
    0x0C, 0x88, 0xE1, 0x41, 0x41, 0x26, 0x8A, 0x01,
    0xAA, 0xE2, 0xFA, 0xEB, 0xA6, 0xAC, 0x08, 0xC0,
    0x74, 0x34, 0x3C, 0x01, 0x74, 0x05, 0x88, 0xC1,
    0x41, 0xEB, 0xEA, 0x89, 0xFB, 0x83, 0xE7, 0x0F,
    0x81, 0xC7, 0x00, 0x20, 0xB1, 0x04, 0xD3, 0xEB,
    0x8C, 0xC0, 0x01, 0xD8, 0x2D, 0x00, 0x02, 0x8E,
    0xC0, 0x89, 0xF3, 0x83, 0xE6, 0x0F, 0xD3, 0xEB,
    0x8C, 0xD8, 0x01, 0xD8, 0x8E, 0xD8, 0xE9, 0x72
]

PKLiteSignature: [
	0xEB, 0x38, 0xAD, 0x95, 0xB2, 0x10, 0xEB, 0x39, 0xAD, 0x95, 0xB2, 0x10
]

file-format exe-DOS
{
	unsigned16 magic == 0x5A4D
	unsigned16 bytesInLastBlock
	unsigned16 blockCount
	unsigned16 relocationCount
	unsigned16 headerParagraphs
	unsigned16 minExtraParagraphs
	unsigned16 maxExtraParagraphs
	unsigned16 ss
  	unsigned16 sp
  	unsigned16 checksum
  	unsigned16 ip
  	unsigned16 cs
  	unsigned16 relocationTableOffset
  	unsigned16 overlay

	//Test for LZExe 90 and LZExe 91 - these values will be picked up internally, no need to mark compressed
	LZVersion: 0
	exe-compression: ""

	if ((overlay == 0) and (relocationTableOffset == 0x1C))
	{
		CodeOffset: ((headerParagraphs + cs) << 4) + ip		

		if (CodeOffset + 232 <= file.size)
		{			
			at CodeOffset
			{
				unsigned8[232] lz-check

				if (LZ90Signature == lz-check)
				{
					exe-compression = "LZEXE"
					LZVersion = 90
				}
				else if (LZ91Signature == lz-check)
				{
					exe-compression = "LZEXE"
					LZVersion = 91
				}						
			}
		}
	}

	at 0x1C
	{
		unsigned8 minor-version
		pklite-version: minor-version
	}
	at 0x1D
	{
		unsigned8 pklite-bitmap
		pklite-major: pklite-bitmap & 0xF
		pklite-extra: ((pklite-bitmap >> 4) & 1) != 0
		pklite-multi-segment: ((pklite-bitmap >> 5) & 1) != 0
	}



	at 0x00
	{
		found: false
		found-beta: false
		beta-large: false

		at file.size - 27
		{
			unsigned8[23] beta-check
			
			if (beta-check == [0x01, 0x02, 0x00, 0x00, 0x03, 0x04, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D])
			{
				found-beta = true
				found = true
				pklite-version = 0

				at file.size - 28
				{
					unsigned8 beta-large-check
					beta-large = (beta-large-check == 0x18)
				}
			}
		}

		//Look for PKLite signature A
		if (!found)
		{
			loop (0x100): i
			{
				at (headerParagraphs * 16 + i):

				unsigned8[0x12] pklite-compare
				if (PKLiteSignature == pklite-compare)
				{
					found = true
				}
			}
		}

		//Look for PKLite signature B
		if (!found)
		{
			loop (0x20): i
			{
				if (!found)
				{
					at (headerParagraphs * 16) + i:
                    unsigned8 findJump

                    if (findJump == 0x72)
                    {
                        unsigned8 notImportant

                        //Test mov ax, 9
                        unsigned16 test2
                        if (test2 == 0x09B4)
                        {
                        	unsigned8 test3
                            if (test3 == 0xBA)
                            {
                                unsigned16 notImportant2
                                unsigned32 sig2
                                if (sig2 == 0x20CD21CD)
                                {
                                    found = true
                                }
                                else if (sig2 == 0x4CB421CD)
                                {
                                    found = true
                                }
                            }
                        }
                    }
                    else if (findJump == 0x73)
                    {
                        signed8 jumpTo
                        at file.position + jumpTo:

                        //Test mov ax, 9
                        unsigned16 test4
                        if (test4 == 0x09B4)
                        {
                        	unsigned8 test5
                            if (test5 == 0xBA)
                            {
                                unsigned16 notImportant2
                                unsigned32 test6
                                if (test6 == 0x20CD21CD)
                                {
                                    found = true
                                }
                            }
                        }
                    }
				}
			}
		}
		
		if (found)
		{
			//The bitmap sometimes lies. Do some deeper detection
			deep-found: false

			if (found-beta) //we found beta version, we've ignored bitmap already
			{
				deep-found = true
			}

			if (!deep-found)
			{
				at (headerParagraphs * 16) + 38
				{
					unsigned8 check1
					if (check1 == 0xBE)
					{
						unsigned16 check2
						if ((check2 == 328) and !(pklite-version like [0, 3, 5]))
						{
							pklite-version = 3 //TODO: work out how to differentiate 1.00, 1.03, 1.05
							deep-found = true
						}
					}
				}
			}

			if (deep-found == false)
			{
				//Check for v.12 / v.13
				at (headerParagraphs * 16) + 34
				{
					unsigned8 check1
					if (check1 == 0xBE)
					{
						unsigned16 check2
						if (check2 == 324)
						{
							pklite-version = 12 //or 13 - but deepscan below will fix up

							at (headerParagraphs * 16) + 227:
                            unsigned8 check3
                            if (check3 == 102)
                            {
                                pklite-version = 12
                            }
                            else if (check3 == 104)
                            {
                                pklite-version = 13
                            }
                            else if (check3 == 249)
                            {
                            	at (headerParagraphs * 16) + 224:
                                unsigned8 check4
                                if (check4 == 94)
                                {
                                    pklite-version = 12
                                }
                                else if (check4 == 96)
                                {
                                    pklite-version = 13
                                }
                            }
                            else if (check3 == 178)
                            {
                                at (headerParagraphs * 16) + 257:
                                unsigned8 check5
                                if (check5 == 124)
                                {
                                    pklite-version = 12
                                }
                                else if (check5 == 125)
                                {
                                    pklite-version = 13
                                }
                            }
                            else if (check3 == 237)
                            {
                                at (headerParagraphs * 16) + 260:
                                unsigned8 check6
                                if (check6 == 124)
                                {
                                    pklite-version = 12
                                }
                                else if (check6 == 125)
                                {
                                    pklite-version = 13
                                }
                            }
							deep-found = true
						}
					}
				}	
			}	

			//Check for v1.14
			if (deep-found == false)
            {
                at (headerParagraphs * 16 + 59)
                {
	                unsigned8 check1
	                if (check1 == 0xBE)
	                {
	                    unsigned16 check2
	                    if (check2 == 322)
	                    {
	                        pklite-version = 14
							deep-found = true
	                    }
	                }
                }
            }	

            //Check for v1.15
			if (deep-found == false)
            {
                at (headerParagraphs * 16 + 52)
                {
	                unsigned8 check1
	                if (check1 == 0xB9)
	                {
	                    unsigned16 check2
	                    if ((check2 == 311) or (check2 == 217))
	                    {
	                        pklite-version = 15
							deep-found = true
	                    }
	                }
                }
            }
            if (deep-found == false)
            {
                at (headerParagraphs * 16 + 54)
                {
	                unsigned8 check1
	                if (check1 == 0xB9)
	                {
	                    unsigned16 check2
	                    if ((check2 == 196) or (check2 == 291))
	                    {
	                        pklite-version = 15
							deep-found = true
	                    }
	                }
                }
            }	

			if (pklite-version like [0, 3, 5, 10, 12, 13, 14, 15/*, 20*/])
			{
				exe-compression = "PKLITE"
			}

			version-string: "PKLite " + pklite-version + " "
			if (pklite-extra == true) {
				version-string = version-string + "E"
			}
			if (pklite-multi-segment == true) {
				version-string = version-string + "L"
			}
			
			/*if (exe-compression != "PKLITE") {
				log("Cannot decompress " + version-string)
			} else {
				log("Can decompress " + version-string)
			}*/

			if (exe-compression != "PKLITE") {
				compress-info: "Cannot decompress " + version-string
			}
		}							
	} 

	//Detect EXEPACK
	exepack-start: ((headerParagraphs + cs) * 16) + ip

	if (exepack-start < file.size)
	{
		at exepack-start - 2:

		unsigned16 exepack-test

		if (exepack-test == 0x4252)
		{
			exepack-header-start: ((headerParagraphs + cs) * 16)
			at exepack-header-start
			{
				unsigned16 real-IP
				unsigned16 real-CS
				unsigned16 mem-start
				unsigned16 exepack-size
				unsigned16 real-SP
				unsigned16 real-SS
				unsigned16 dest-len

				if (ip == 18) {
					unsigned16 skip-len
				}

				unsigned16 exepack-signature //RB
			}

			exe-compression = "EXEPACK"
			//log("Can decompress EXEPACK")
		}
	}


	//at relocationTableOffset:
	//foreach[relocationCount]
	//(
	//	unsigned16 offset
	//	unsigned16 segment
	//)

	//Rest is exe data.
}