/* 
 * Copyright (c) [2010-2019] zhenfei.mzf@gmail.com rights reserved.
 * 
 * AntiSpy is licensed under the Mulan PSL v1.
 * You can use this software according to the terms and conditions of the Mulan PSL v1.
 * You may obtain a copy of Mulan PSL v1 at:
 *
 *     http://license.coscl.org.cn/MulanPSL
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR
 * FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v1 for more details.
*/
// Free Disassembler and Assembler -- Disassembler
//
// Copyright (C) 2001 Oleh Yuschuk
//
//  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
#define _CRT_SECURE_NO_WARNINGS
#define STRICT
#pragma warning(disable:4996)  
#pragma warning(disable:4244)

#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
//#include <dir.h>
#include <math.h>
#include <float.h>
#pragma hdrstop

#include "disasm.h"

////////////////////////////////////////////////////////////////////////////////
//////////////////////////// DISASSEMBLER FUNCTIONS ////////////////////////////

// Work variables of disassembler
static ulong     datasize;             // Size of data (1,2,4 bytes)
static ulong     addrsize;             // Size of address (2 or 4 bytes)
static int       segprefix;            // Segment override prefix or SEG_UNDEF
static int       hasrm;                // Command has ModR/M byte
static int       hassib;               // Command has SIB byte
static int       dispsize;             // Size of displacement (if any)
static int       immsize;              // Size of immediate data (if any)
static int       softerror;            // Noncritical disassembler error
static int       ndump;                // Current length of command dump
static int       nresult;              // Current length of disassembly
static int       addcomment;           // Comment value of operand

// Copy of input parameters of function Disasm()
static byte      *cmd;                 // Pointer to binary data
static byte      *pfixup;              // Pointer to possible fixups or NULL
static ulong     size;                 // Remaining size of the command buffer
static t_disasm  *da;                  // Pointer to disassembly results
static int       mode;                 // Disassembly mode (DISASM_xxx)

// Disassemble name of 1, 2 or 4-byte general-purpose integer register and, if
// requested and available, dump its contents. Parameter type changes decoding
// of contents for some operand types.
static void DecodeRG(int index,int datasize,int type) {
	int sizeindex;
	char name[9];
	if (mode<DISASM_DATA) return;        // No need to decode
	index&=0x07;
	if (datasize==1)
		sizeindex=0;
	else if (datasize==2)
		sizeindex=1;
	else if (datasize==4)
		sizeindex=2;
	else {
		da->error=DAE_INTERN; return; };
		if (mode>=DISASM_FILE) {
			strcpy(name,regname[sizeindex][index]);
			if (lowercase) strlwr(name);
			if (type<PSEUDOOP)                 // Not a pseudooperand
				nresult+=sprintf(da->result+nresult,"%s",name);
			;
		};
};

// Disassemble name of 80-bit floating-point register and, if available, dump
// its contents.
static void DecodeST(int index,int pseudoop) {
	int i;
	char s[32];
	if (mode<DISASM_FILE) return;        // No need to decode
	index&=0x07;
	i=sprintf(s,"%s(%i)",(lowercase?"st":"ST"),index);
	if (pseudoop==0) {
		strcpy(da->result+nresult,s);
		nresult+=i;
	};
};

// Disassemble name of 64-bit MMX register.
static void DecodeMX(int index) {
	char *pr;
	if (mode<DISASM_FILE) return;        // No need to decode
	index&=0x07;
	pr=da->result+nresult;
	nresult+=sprintf(pr,"%s%i",(lowercase?"mm":"MM"),index);
};

// Disassemble name of 64-bit 3DNow! register and, if available, dump its
// contents.
static void DecodeNR(int index) {
	char *pr;
	if (mode<DISASM_FILE) return;        // No need to decode
	index&=0x07;
	pr=da->result+nresult;
	nresult+=sprintf(pr,"%s%i",(lowercase?"mm":"MM"),index);
};

// Service function, adds valid memory adress in MASM or Ideal format to
// disassembled string. Parameters: defseg - default segment for given
// register combination, descr - fully decoded register part of address,
// offset - constant part of address, dsize - data size in bytes. If global
// flag 'symbolic' is set, function also tries to decode offset as name of
// some label.
static void Memadr(int defseg,const char *descr,long offset,int dsize) {
	int i,n,seg;
	char *pr;
	char s[TEXTLEN];
	if (mode<DISASM_FILE || descr==NULL)
		return;                            // No need or possibility to decode
	pr=da->result+nresult; n=0;
	if (segprefix!=SEG_UNDEF) seg=segprefix; else seg=defseg;
	if (ideal!=0) pr[n++]='[';
	// In some cases Disassembler may omit size of memory operand. Namely, flag
	// showmemsize must be 0, type bit C_EXPL must be 0 (this bit namely means
	// that explicit operand size is necessary) and type of command must not be
	// C_MMX or C_NOW (because bit C_EXPL has in these cases different meaning).
	// Otherwise, exact size must be supplied.
	if (showmemsize!=0 || (da->cmdtype & C_TYPEMASK)==C_MMX ||
		(da->cmdtype & C_TYPEMASK)==C_NOW || (da->cmdtype & C_EXPL)!=0
		) {
			if (dsize<sizeof(sizename)/sizeof(sizename[0]))
				n+=sprintf(pr+n,"%s %s",sizename[dsize],(ideal==0?"PTR ":""));
			else
				n+=sprintf(pr+n,"(%i-BYTE) %s",dsize,(ideal==0?"PTR ":""));
			;
	};
	if ((putdefseg!=0 || seg!=defseg) && seg!=SEG_UNDEF)
		n+=sprintf(pr+n,"%s:",segname[seg]);
	if (ideal==0) pr[n++]='[';
	n+=sprintf(pr+n,"%s",descr);
	if (lowercase) strlwr(pr);
	if (offset==0L) {
		if (*descr=='\0') pr[n++]='0'; }
	else {
		if (symbolic && mode>=DISASM_CODE)
			i=Decodeaddress(offset,s,TEXTLEN-n-24,NULL);
		else i=0;
		if (i>0) {                         // Offset decoded in symbolic form
			if (*descr!='\0') pr[n++]='+';
			strcpy(pr+n,s); n+=i; }
		else if (offset<0 && offset>-16384 && *descr!='\0')
			n+=sprintf(pr+n,"-%lX",-offset);
		else {
			if (*descr!='\0') pr[n++]='+';
			n+=sprintf(pr+n,"%lX",offset);
		};
	};
	pr[n++]=']'; pr[n]='\0';
	nresult+=n;
};

// Disassemble memory/register from the ModRM/SIB bytes and, if available, dump
// address and contents of memory.
static void DecodeMR(int type) {
	int j,memonly,inmemory,seg;
	int c,sib;
	ulong dsize,regsize,addr;
	char s[TEXTLEN];
	if (size<2) {
		da->error=DAE_CROSS; return; };    // ModR/M byte outside the memory block
		hasrm=1;
		dsize=regsize=datasize;              // Default size of addressed reg/memory
		memonly=0;                           // Register in ModM field is allowed
		// Size and kind of addressed memory or register in ModM has no influence on
		// the command size, and exact calculations are omitted if only command size
		// is requested. If register is used, optype will be incorrect and we need
		// to correct it later.
		c=cmd[1] & 0xC7;                     // Leave only Mod and M fields
		if (mode>=DISASM_DATA) {
			if ((c & 0xC0)==0xC0)              // Register operand
				inmemory=0;
			else                               // Memory operand
				inmemory=1;
			switch (type) {
	  case MRG:                        // Memory/register in ModRM byte
		  if (inmemory) {
			  if (datasize==1) da->memtype=DEC_BYTE;
			  else if (datasize==2) da->memtype=DEC_WORD;
			  else da->memtype=DEC_DWORD; };
			  break;
	  case MRJ:                        // Memory/reg in ModRM as JUMP target
		  if (datasize!=2 && inmemory)
			  da->memtype=DEC_DWORD; 
		  if (mode>=DISASM_FILE && shownear!=0)
			  nresult+=sprintf(da->result+nresult,"%s ",(lowercase?"near":"NEAR"));
		  break;
	  case MR1:                        // 1-byte memory/register in ModRM byte
		  dsize=regsize=1;
		  if (inmemory) da->memtype=DEC_BYTE; break;
	  case MR2:                        // 2-byte memory/register in ModRM byte
		  dsize=regsize=2;
		  if (inmemory) da->memtype=DEC_WORD; break;
	  case MR4:                        // 4-byte memory/register in ModRM byte
	  case RR4:                        // 4-byte memory/register (register only)
		  dsize=regsize=4;
		  if (inmemory) da->memtype=DEC_DWORD; break;
	  case MR8:                        // 8-byte memory/MMX register in ModRM
	  case RR8:                        // 8-byte MMX register only in ModRM
		  dsize=8;
		  if (inmemory) da->memtype=DEC_QWORD; break;
	  case MRD:                        // 8-byte memory/3DNow! register in ModRM
	  case RRD:                        // 8-byte memory/3DNow! (register only)
		  dsize=8;
		  if (inmemory) da->memtype=DEC_3DNOW; break;
	  case MMA:                        // Memory address in ModRM byte for LEA
		  memonly=1; break;
	  case MML:                        // Memory in ModRM byte (for LES)
		  dsize=datasize+2; memonly=1;
		  if (datasize==4 && inmemory)
			  da->memtype=DEC_FWORD;
		  da->warnings|=DAW_SEGMENT;
		  break;
	  case MMS:                        // Memory in ModRM byte (as SEG:OFFS)
		  dsize=datasize+2; memonly=1;
		  if (datasize==4 && inmemory)
			  da->memtype=DEC_FWORD;
		  if (mode>=DISASM_FILE)
			  nresult+=sprintf(da->result+nresult,"%s ",(lowercase?"far":"FAR"));
		  break;
	  case MM6:                        // Memory in ModRM (6-byte descriptor)
		  dsize=6; memonly=1;
		  if (inmemory) da->memtype=DEC_FWORD; break;
	  case MMB:                        // Two adjacent memory locations (BOUND)
		  dsize=(ideal?datasize:datasize*2); memonly=1; break;
	  case MD2:                        // Memory in ModRM byte (16-bit integer)
	  case MB2:                        // Memory in ModRM byte (16-bit binary)
		  dsize=2; memonly=1;
		  if (inmemory) da->memtype=DEC_WORD; break;
	  case MD4:                        // Memory in ModRM byte (32-bit integer)
		  dsize=4; memonly=1;
		  if (inmemory) da->memtype=DEC_DWORD; break;
	  case MD8:                        // Memory in ModRM byte (64-bit integer)
		  dsize=8; memonly=1;
		  if (inmemory) da->memtype=DEC_QWORD; break;
	  case MDA:                        // Memory in ModRM byte (80-bit BCD)
		  dsize=10; memonly=1;
		  if (inmemory) da->memtype=DEC_TBYTE; break;
	  case MF4:                        // Memory in ModRM byte (32-bit float)
		  dsize=4; memonly=1;
		  if (inmemory) da->memtype=DEC_FLOAT4; break;
	  case MF8:                        // Memory in ModRM byte (64-bit float)
		  dsize=8; memonly=1;
		  if (inmemory) da->memtype=DEC_FLOAT8; break;
	  case MFA:                        // Memory in ModRM byte (80-bit float)
		  dsize=10; memonly=1;
		  if (inmemory) da->memtype=DEC_FLOAT10; break;
	  case MFE:                        // Memory in ModRM byte (FPU environment)
		  dsize=28; memonly=1; break;
	  case MFS:                        // Memory in ModRM byte (FPU state)
		  dsize=108; memonly=1; break;
	  case MFX:                        // Memory in ModRM byte (ext. FPU state)
		  dsize=512; memonly=1; break;
	  default:                         // Operand is not in ModM!
		  da->error=DAE_INTERN;
		  break;
			};
		};
		addr=0;
		// There are many possibilities to decode ModM/SIB address. The first
		// possibility is register in ModM - general-purpose, MMX or 3DNow!
		if ((c & 0xC0)==0xC0) {              // Decode register operand
			if (type==MR8 || type==RR8)
				DecodeMX(c);                     // MMX register
			else if (type==MRD || type==RRD)
				DecodeNR(c);                     // 3DNow! register
			else  
				DecodeRG(c,regsize,type);        // General-purpose register
			if (memonly!=0)
				softerror=DAE_MEMORY;            // Register where only memory allowed
			return; };
			// Next possibility: 16-bit addressing mode, very seldom in 32-bit flat model
			// but still supported by processor. SIB byte is never used here.
			if (addrsize==2) {
				if (c==0x06) {                     // Special case of immediate address
					dispsize=2;
					if (size<4)
						da->error=DAE_CROSS;           // Disp16 outside the memory block
					else if (mode>=DISASM_DATA) {
						da->adrconst=addr=*(ushort *)(cmd+2);
						if (addr==0) da->zeroconst=1;
						seg=SEG_DS;
						Memadr(seg,"",addr,dsize);
					}; }
				else {
					da->indexed=1;
					if ((c & 0xC0)==0x40) {          // 8-bit signed displacement
						if (size<3) da->error=DAE_CROSS;
						else addr=(signed char)cmd[2] & 0xFFFF;
						dispsize=1; }
					else if ((c & 0xC0)==0x80) {     // 16-bit unsigned displacement
						if (size<4) da->error=DAE_CROSS;
						else addr=*(ushort *)(cmd+2);
						dispsize=2; };
						if (mode>=DISASM_DATA && da->error==DAE_NOERR) {
							da->adrconst=addr;
							if (addr==0) da->zeroconst=1;
							seg=addr16[c & 0x07].defseg;
							Memadr(seg,addr16[c & 0x07].descr,addr,dsize);
						};
				};
			}
			// Next possibility: immediate 32-bit address.
			else if (c==0x05) {                  // Special case of immediate address
				dispsize=4;
				if (size<6)
					da->error=DAE_CROSS;             // Disp32 outside the memory block
				else if (mode>=DISASM_DATA) {
					da->adrconst=addr=*(ulong *)(cmd+2);
					if (pfixup==NULL) pfixup=cmd+2;
					da->fixupsize+=4;
					if (addr==0) da->zeroconst=1;
					seg=SEG_DS;
					Memadr(seg,"",addr,dsize);
				}; }
			// Next possibility: 32-bit address with SIB byte.
			else if ((c & 0x07)==0x04) {         // SIB addresation
				sib=cmd[2]; hassib=1;
				*s='\0';
				if (c==0x04 && (sib & 0x07)==0x05) {
					dispsize=4;                      // Immediate address without base
					if (size<7)
						da->error=DAE_CROSS;           // Disp32 outside the memory block
					else {
						da->adrconst=addr=*(ulong *)(cmd+3);
						if (pfixup==NULL) pfixup=cmd+3;
						da->fixupsize+=4;
						if (addr==0) da->zeroconst=1;
						if ((sib & 0x38)!=0x20) {      // Index register present
							da->indexed=1;
							if (type==MRJ) da->jmptable=addr; };
							seg=SEG_DS;
					}; }
				else {                             // Base and, eventually, displacement
					if ((c & 0xC0)==0x40) {          // 8-bit displacement
						dispsize=1;
						if (size<4) da->error=DAE_CROSS;
						else {
							da->adrconst=addr=(signed char)cmd[3];
							if (addr==0) da->zeroconst=1;
						}; }
					else if ((c & 0xC0)==0x80) {     // 32-bit displacement
						dispsize=4;
						if (size<7)
							da->error=DAE_CROSS;         // Disp32 outside the memory block
						else {
							da->adrconst=addr=*(ulong *)(cmd+3);
							if (pfixup==NULL) pfixup=cmd+3;
							da->fixupsize+=4;
							if (addr==0) da->zeroconst=1;
							// Most compilers use address of type [index*4+displacement] to
							// address jump table (switch). But, for completeness, I allow all
							// cases which include index with scale 1 or 4, base or both.
							if (type==MRJ) da->jmptable=addr;
						}; };
						da->indexed=1;
						j=sib & 0x07;
						if (mode>=DISASM_FILE) {
							strcpy(s,regname[2][j]);
							seg=addr32[j].defseg;
						};
				};
				if ((sib & 0x38)!=0x20) {          // Scaled index present
					if ((sib & 0xC0)==0x40) da->indexed=2;
					else if ((sib & 0xC0)==0x80) da->indexed=4;
					else if ((sib & 0xC0)==0xC0) da->indexed=8;
					else da->indexed=1;
				};
				if (mode>=DISASM_FILE && da->error==DAE_NOERR) {
					if ((sib & 0x38)!=0x20) {        // Scaled index present
						if (*s!='\0') strcat(s,"+");
						strcat(s,addr32[(sib>>3) & 0x07].descr);
						if ((sib & 0xC0)==0x40) {
							da->jmptable=0;              // Hardly a switch!
							strcat(s,"*2"); }
						else if ((sib & 0xC0)==0x80)
							strcat(s,"*4");
						else if ((sib & 0xC0)==0xC0) {
							da->jmptable=0;              // Hardly a switch!
							strcat(s,"*8");
						};
					};
					Memadr(seg,s,addr,dsize);
				};
			}
			// Last possibility: 32-bit address without SIB byte.
			else {                               // No SIB
				if ((c & 0xC0)==0x40) {
					dispsize=1;
					if (size<3) da->error=DAE_CROSS; // Disp8 outside the memory block
					else {
						da->adrconst=addr=(signed char)cmd[2];
						if (addr==0) da->zeroconst=1;
					}; }
				else if ((c & 0xC0)==0x80) {
					dispsize=4;
					if (size<6)
						da->error=DAE_CROSS;           // Disp32 outside the memory block
					else {
						da->adrconst=addr=*(ulong *)(cmd+2);
						if (pfixup==NULL) pfixup=cmd+2;
						da->fixupsize+=4;
						if (addr==0) da->zeroconst=1;
						if (type==MRJ) da->jmptable=addr;
					};
				};
				da->indexed=1;
				if (mode>=DISASM_FILE && da->error==DAE_NOERR) {
					seg=addr32[c & 0x07].defseg;
					Memadr(seg,addr32[c & 0x07].descr,addr,dsize);
				};
			};
};

// Disassemble implicit source of string operations and, if available, dump
// address and contents.
static void DecodeSO(void) {
	if (mode<DISASM_FILE) return;        // No need to decode
	if (datasize==1) da->memtype=DEC_BYTE;
	else if (datasize==2) da->memtype=DEC_WORD;
	else if (datasize==4) da->memtype=DEC_DWORD;
	da->indexed=1;
	Memadr(SEG_DS,regname[addrsize==2?1:2][REG_ESI],0L,datasize);
};

// Disassemble implicit destination of string operations and, if available,
// dump address and contents. Destination always uses segment ES, and this
// setting cannot be overridden.
static void DecodeDE(void) {
	int seg;
	if (mode<DISASM_FILE) return;        // No need to decode
	if (datasize==1) da->memtype=DEC_BYTE;
	else if (datasize==2) da->memtype=DEC_WORD;
	else if (datasize==4) da->memtype=DEC_DWORD;
	da->indexed=1;
	seg=segprefix; segprefix=SEG_ES;     // Fake Memadr by changing segment prefix
	Memadr(SEG_DS,regname[addrsize==2?1:2][REG_EDI],0L,datasize);
	segprefix=seg;                       // Restore segment prefix
};

// Decode XLAT operand and, if available, dump address and contents.
static void DecodeXL(void) {
	if (mode<DISASM_FILE) return;        // No need to decode
	da->memtype=DEC_BYTE;
	da->indexed=1;
	Memadr(SEG_DS,(addrsize==2?"BX+AL":"EBX+AL"),0L,1);
};

// Decode immediate operand of size constsize. If sxt is non-zero, byte operand
// should be sign-extended to sxt bytes. If type of immediate constant assumes
// this, small negative operands may be displayed as signed negative numbers.
// Note that in most cases immediate operands are not shown in comment window.
static void DecodeIM(int constsize,int sxt,int type) {
	int i;
	signed long data;
	ulong l;
	char name[TEXTLEN],comment[TEXTLEN];
	immsize+=constsize;                    // Allows several immediate operands
	if (mode<DISASM_DATA) return;
	l=1+hasrm+hassib+dispsize+(immsize-constsize);
	data=0;
	if (size<l+constsize)
		da->error=DAE_CROSS;
	else if (constsize==1) {
		if (sxt==0) data=(uchar)cmd[l];
		else data=(signed char)cmd[l];
		if (type==IMS && ((data & 0xE0)!=0 || data==0)) {
			da->warnings|=DAW_SHIFT;
			da->cmdtype|=C_RARE;
		}; }
	else if (constsize==2) {
		if (sxt==0) data=*(ushort *)(cmd+l);
		else data=*(short *)(cmd+l); }
	else {
		data=*(long *)(cmd+l);
		if (pfixup==NULL) pfixup=cmd+l;
		da->fixupsize+=4; };
		if (sxt==2) data&=0x0000FFFF;
		if (data==0 && da->error==0) da->zeroconst=1;
		// Command ENTER, as an exception from Intel's rules, has two immediate
		// constants. As the second constant is rarely used, I exclude it from
		// search if the first constant is non-zero (which is usually the case).
		if (da->immconst==0)
			da->immconst=data;

		//反汇编代码注释部分，由Decodeaddress实现注释。
		if (mode>=DISASM_FILE && da->error==DAE_NOERR)
		{
			if (mode>=DISASM_CODE && type!=IMU)
				i=Decodeaddress(data,name,TEXTLEN-nresult-24,comment);
			else 
			{
				i=0; comment[0]='\0'; 
			};
			if (i!=0 && symbolic!=0) 
			{
				strcpy(da->result+nresult,name); nresult+=i; 
			}
			else if (type==IMU || type==IMS || type==IM2 || data>=0 || data<NEGLIMIT)
				nresult+=sprintf(da->result+nresult,"%lX",data);
			else
				nresult+=sprintf(da->result+nresult,"-%lX",-data);
			//if (addcomment && comment[0]!='\0')
			//	strcpy(da->comment,comment);
		};
};

// Decode VxD service name (always 4-byte).
static void DecodeVX(void) {
	ulong l,data;
	immsize+=4;                          // Allows several immediate operands
	if (mode<DISASM_DATA) return;
	l=1+hasrm+hassib+dispsize+(immsize-4);
	if (size<l+4) {
		da->error=DAE_CROSS;
		return; };
		data=*(long *)(cmd+l);
		if (data==0 && da->error==0) da->zeroconst=1;
		if (da->immconst==0)
			da->immconst=data;
		if (mode>=DISASM_FILE && da->error==DAE_NOERR) {
			if ((data & 0x00008000)!=0 && memicmp("VxDCall",da->result,7)==0)
				memcpy(da->result,lowercase?"vxdjump":"VxDJump",7);
			nresult+=sprintf(da->result+nresult,"%lX",data);
		};
};

// Decode implicit constant 1 (used in shift commands). This operand is so
// insignificant that it is never shown in comment window.
static void DecodeC1(void) {
	if (mode<DISASM_DATA) return;
	da->immconst=1;
	if (mode>=DISASM_FILE) nresult+=sprintf(da->result+nresult,"1");
};

// Decode immediate absolute data address. This operand is used in 8080-
// compatible commands which allow to move data from memory to accumulator and
// back. Note that bytes ModRM and SIB never appear in commands with IA operand.
static void DecodeIA(void) {
	ulong addr;
	if (size<1+addrsize) {
		da->error=DAE_CROSS; return; };
		dispsize=addrsize;
		if (mode<DISASM_DATA) return;
		if (datasize==1) da->memtype=DEC_BYTE;
		else if (datasize==2) da->memtype=DEC_WORD;
		else if (datasize==4) da->memtype=DEC_DWORD;
		if (addrsize==2)
			addr=*(ushort *)(cmd+1);
		else {
			addr=*(ulong *)(cmd+1);
			if (pfixup==NULL) pfixup=cmd+1;
			da->fixupsize+=4; };
			da->adrconst=addr;
			if (addr==0) da->zeroconst=1;
			if (mode>=DISASM_FILE) {
				Memadr(SEG_DS,"",addr,datasize);
			};
};

// Decodes jump relative to nextip of size offsize.
static void DecodeRJ(ulong offsize,ulong nextip) {
	int i;
	ulong addr;
	char s[TEXTLEN];
	if (size<offsize+1) {
		da->error=DAE_CROSS; return; };
		dispsize=offsize;                    // Interpret offset as displacement
		if (mode<DISASM_DATA) return;
		if (offsize==1)
			addr=(signed char)cmd[1]+nextip;
		else if (offsize==2)
			addr=*(signed short *)(cmd+1)+nextip;
		else
			addr=*(ulong *)(cmd+1)+nextip;
		if (datasize==2)
			addr&=0xFFFF;
		da->jmpconst=addr;
		if (addr==0) da->zeroconst=1;
		if (mode>=DISASM_FILE) {
			if (offsize==1) nresult+=sprintf(da->result+nresult,
				"%s ",(lowercase==0?"SHORT":"short"));
			if (mode>=DISASM_CODE)
				i=Decodeaddress(addr,s,TEXTLEN,da->comment);
			else
				i=0;
			if (symbolic==0 || i==0)
				nresult+=sprintf(da->result+nresult,"%08lX",addr);
			else
				nresult+=sprintf(da->result+nresult,"%.*s",TEXTLEN-nresult-25,s);
			if (symbolic==0 && i!=0 && da->comment[0]=='\0')
				strcpy(da->comment,s);
			;
		};
};

// Decode immediate absolute far jump address. In flat model, such addresses
// are not used (mostly because selector is specified directly in the command),
// so I neither decode as symbol nor comment it. To allow search for selector
// by value, I interprete it as an immediate constant.
static void DecodeJF(void) {
	ulong addr,seg;
	if (size<1+addrsize+2) {
		da->error=DAE_CROSS; return; };
		dispsize=addrsize; immsize=2;        // Non-trivial but allowed interpretation
		if (mode<DISASM_DATA) return;
		if (addrsize==2) {
			addr=*(ushort *)(cmd+1);
			seg=*(ushort *)(cmd+3); }
		else {
			addr=*(ulong *)(cmd+1);
			seg=*(ushort *)(cmd+5); };
			da->jmpconst=addr;
			da->immconst=seg;
			if (addr==0 || seg==0) da->zeroconst=1;
			if (mode>=DISASM_FILE) {
				nresult+=sprintf(da->result+nresult,"%s %04X:%08X",
					(lowercase==0?"FAR":"far"),seg,addr);
			};
};

// Decode segment register. In flat model, operands of this type are seldom.
static void DecodeSG(int index) {
	int i;
	if (mode<DISASM_DATA) return;
	index&=0x07;
	if (index>=6) softerror=DAE_BADSEG;  // Undefined segment register
	if (mode>=DISASM_FILE) {
		i=sprintf(da->result+nresult,"%s",segname[index]);
		if (lowercase) strlwr(da->result+nresult);
		nresult+=i;
	};
};

// Decode control register addressed in R part of ModRM byte. Operands of
// this type are extremely rare. Contents of control registers are accessible
// only from privilege level 0, so I cannot dump them here.
static void DecodeCR(int index) {
	hasrm=1;
	if (mode>=DISASM_FILE) {
		index=(index>>3) & 0x07;
		nresult+=sprintf(da->result+nresult,"%s",crname[index]);
		if (lowercase) strlwr(da->result+nresult);
	};
};

// Decode debug register addressed in R part of ModRM byte. Operands of
// this type are extremely rare. I can dump only those debug registers
// available in CONTEXT structure.
static void DecodeDR(int index) {
	int i;
	hasrm=1;
	if (mode>=DISASM_FILE) {
		index=(index>>3) & 0x07;
		i=sprintf(da->result+nresult,"%s",drname[index]);
		if (lowercase) strlwr(da->result+nresult);
		nresult+=i;
	};
};

// Skips 3DNow! operands and extracts command suffix. Returns suffix or -1 if
// suffix lies outside the memory block. This subroutine assumes that cmd still
// points to the beginning of 3DNow! command (i.e. to the sequence of two bytes
// 0F, 0F).
static int Get3dnowsuffix(void) {
	int c,sib;
	ulong offset;
	if (size<3) return -1;               // Suffix outside the memory block
	offset=3;
	c=cmd[2] & 0xC7;                     // Leave only Mod and M fields
	// Register in ModM - general-purpose, MMX or 3DNow!
	if ((c & 0xC0)==0xC0)
		;
	// 16-bit addressing mode, SIB byte is never used here.
	else if (addrsize==2) {
		if (c==0x06)                       // Special case of immediate address
			offset+=2;
		else if ((c & 0xC0)==0x40)         // 8-bit signed displacement
			offset++;
		else if ((c & 0xC0)==0x80)         // 16-bit unsigned displacement
			offset+=2;
		; }
	// Immediate 32-bit address.
	else if (c==0x05)                    // Special case of immediate address
		offset+=4;
	// 32-bit address with SIB byte.
	else if ((c & 0x07)==0x04) {         // SIB addresation
		if (size<4) return -1;             // Suffix outside the memory block
		sib=cmd[3]; offset++;
		if (c==0x04 && (sib & 0x07)==0x05)
			offset+=4;                       // Immediate address without base
		else if ((c & 0xC0)==0x40)         // 8-bit displacement
			offset+=1;
		else if ((c & 0xC0)==0x80)         // 32-bit dislacement
			offset+=4;
		; }
	// 32-bit address without SIB byte
	else if ((c & 0xC0)==0x40)
		offset+=1;
	else if ((c & 0xC0)==0x80)
		offset+=4;
	if (offset>=size) return -1;         // Suffix outside the memory block
	return cmd[offset];
};

// Function checks whether 80x86 flags meet condition set in the command.
// Returns 1 if condition is met, 0 if not and -1 in case of error (which is
// not possible).
int Checkcondition(int code,ulong flags) {
	ulong cond,temp;
	switch (code & 0x0E) {
	case 0:                            // If overflow
		cond=flags & 0x0800; break;
	case 2:                            // If below
		cond=flags & 0x0001; break;
	case 4:                            // If equal
		cond=flags & 0x0040; break;
	case 6:                            // If below or equal
		cond=flags & 0x0041; break;
	case 8:                            // If sign
		cond=flags & 0x0080; break;
	case 10:                           // If parity
		cond=flags & 0x0004; break;
	case 12:                           // If less
		temp=flags & 0x0880;
		cond=(temp==0x0800 || temp==0x0080); break;
	case 14:                           // If less or equal
		temp=flags & 0x0880;
		cond=(temp==0x0800 || temp==0x0080 || (flags & 0x0040)!=0); break;
	default: return -1;                // Internal error, not possible!
	};
	if ((code & 0x01)==0) return (cond!=0);
	else return (cond==0);               // Invert condition
};

ulong ODDisasm(char *src,ulong srcsize,ulong srcip,
			 t_disasm *disasm,int disasmmode) {
				 int i,j,isprefix,is3dnow,repeated,operand,mnemosize;
				 ulong u,code;
				 int lockprefix;                      // Non-zero if lock prefix present
				 int repprefix;                       // REPxxx prefix or 0
				 int cxsize;
				 byte arg;
				 char name[TEXTLEN],*pname;
				 const t_cmddata *pd,*pdan;
				 // Prepare disassembler variables and initialize structure disasm.
				 datasize=addrsize=4;                 // 32-bit code and data segments only!
				 segprefix=SEG_UNDEF;
				 hasrm=hassib=0; dispsize=immsize=0;
				 lockprefix=0; repprefix=0;
				 ndump=0; nresult=0;
				 cmd=src; size=srcsize; pfixup=NULL;
				 softerror=0; is3dnow=0;
				 da=disasm;
				 da->ip=srcip;
				 da->comment[0]='\0';
				 da->cmdtype=C_BAD; da->nprefix=0;
				 da->memtype=DEC_UNKNOWN; da->indexed=0;
				 da->jmpconst=0; da->jmptable=0;
				 da->adrconst=0; da->immconst=0;
				 da->zeroconst=0;
				 da->fixupoffset=0; da->fixupsize=0;
				 da->warnings=0;
				 da->error=DAE_NOERR;
				 mode=disasmmode;                     // No need to use register contents
				 // Correct 80x86 command may theoretically contain up to 4 prefixes belonging
				 // to different prefix groups. This limits maximal possible size of the
				 // command to MAXCMDSIZE=16 bytes. In order to maintain this limit, if
				 // Disasm() detects second prefix from the same group, it flushes first
				 // prefix in the sequence as a pseudocommand.
				 u=0; repeated=0;
				 while (size>0) {
					 isprefix=1;                        // Assume that there is some prefix
					 switch (*cmd) {
	  case 0x26: if (segprefix==SEG_UNDEF) segprefix=SEG_ES;
				 else repeated=1; break;
	  case 0x2E: if (segprefix==SEG_UNDEF) segprefix=SEG_CS;
				 else repeated=1; break;
	  case 0x36: if (segprefix==SEG_UNDEF) segprefix=SEG_SS;
				 else repeated=1; break;
	  case 0x3E: if (segprefix==SEG_UNDEF) segprefix=SEG_DS;
				 else repeated=1; break;
	  case 0x64: if (segprefix==SEG_UNDEF) segprefix=SEG_FS;
				 else repeated=1; break;
	  case 0x65: if (segprefix==SEG_UNDEF) segprefix=SEG_GS;
				 else repeated=1; break;
	  case 0x66: if (datasize==4) datasize=2;
				 else repeated=1; break;
	  case 0x67: if (addrsize==4) addrsize=2;
				 else repeated=1; break;
	  case 0xF0: if (lockprefix==0) lockprefix=0xF0;
				 else repeated=1; break;
	  case 0xF2: if (repprefix==0) repprefix=0xF2;
				 else repeated=1; break;
	  case 0xF3: if (repprefix==0) repprefix=0xF3;
				 else repeated=1; break;
	  default: isprefix=0; break; };
		  if (isprefix==0 || repeated!=0)
			  break;                           // No more prefixes or duplicated prefix
		  if (mode>=DISASM_FILE)
			  ndump+=sprintf(da->dump+ndump,"%02X:",(BYTE)*cmd);
		  da->nprefix++;
		  cmd++; srcip++; size--; u++; };
		  // We do have repeated prefix. Flush first prefix from the sequence.
		  if (repeated) {
			  if (mode>=DISASM_FILE) {
				  da->dump[3]='\0';                // Leave only first dumped prefix
				  da->nprefix=1;
				  switch (cmd[-(long)u]) {
	  case 0x26: pname=(char *)(segname[SEG_ES]); break;
	  case 0x2E: pname=(char *)(segname[SEG_CS]); break;
	  case 0x36: pname=(char *)(segname[SEG_SS]); break;
	  case 0x3E: pname=(char *)(segname[SEG_DS]); break;
	  case 0x64: pname=(char *)(segname[SEG_FS]); break;
	  case 0x65: pname=(char *)(segname[SEG_GS]); break;
	  case 0x66: pname="DATASIZE"; break;
	  case 0x67: pname="ADDRSIZE"; break;
	  case 0xF0: pname="LOCK"; break;
	  case 0xF2: pname="REPNE"; break;
	  case 0xF3: pname="REPE"; break;
	  default: pname="?"; break; };
		  nresult+=sprintf(da->result+nresult,"PREFIX %s:",pname);
		  if (lowercase) strlwr(da->result);
		  if (extraprefix==0) strcpy(da->comment,"Superfluous prefix"); };
		  da->warnings|=DAW_PREFIX;
		  if (lockprefix) da->warnings|=DAW_LOCK;
		  da->cmdtype=C_RARE;
		  return 1;                          // Any prefix is 1 byte long
		  };
		  // If lock prefix available, display it and forget, because it has no
		  // influence on decoding of rest of the command.
		  if (lockprefix!=0) {
			  if (mode>=DISASM_FILE) nresult+=sprintf(da->result+nresult,"LOCK ");
			  da->warnings|=DAW_LOCK; };
			  // Fetch (if available) first 3 bytes of the command, add repeat prefix and
			  // find command in the command table.
			  code=0;
			  if (size>0) *(((char *)&code)+0)=cmd[0];
			  if (size>1) *(((char *)&code)+1)=cmd[1];
			  if (size>2) *(((char *)&code)+2)=cmd[2];
			  if (repprefix!=0)                    // RER/REPE/REPNE is considered to be
				  code=(code<<8) | repprefix;        // part of command.
			  if (decodevxd && (code & 0xFFFF)==0x20CD)
				  pd=&vxdcmd;                        // Decode VxD call (Win95/98)
			  else {
				  for (pd=cmddata; pd->mask!=0; pd++) {
					  if (((code^pd->code) & pd->mask)!=0) continue;
					  if (mode>=DISASM_FILE && shortstringcmds &&
						  (pd->arg1==MSO || pd->arg1==MDE || pd->arg2==MSO || pd->arg2==MDE))
						  continue;                      // Search short form of string command
					  break;
				  };
			  };
			  if ((pd->type & C_TYPEMASK)==C_NOW) {
				  // 3DNow! commands require additional search.
				  is3dnow=1;
				  j=Get3dnowsuffix();
				  if (j<0)
					  da->error=DAE_CROSS;
				  else {
					  for ( ; pd->mask!=0; pd++) {
						  if (((code^pd->code) & pd->mask)!=0) continue;
						  if (((uchar *)&(pd->code))[2]==j) break;
					  };
				  };
			  };
			  if (pd->mask==0) {                   // Command not found
				  da->cmdtype=C_BAD;
				  if (size<2) da->error=DAE_CROSS;
				  else da->error=DAE_BADCMD; }
			  else {                               // Command recognized, decode it
				  da->cmdtype=pd->type;
				  cxsize=datasize;                   // Default size of ECX used as counter
				  if (segprefix==SEG_FS || segprefix==SEG_GS || lockprefix!=0)
					  da->cmdtype|=C_RARE;             // These prefixes are rare
				  if (pd->bits==PR)
					  da->warnings|=DAW_PRIV;          // Privileged command (ring 0)
				  else if (pd->bits==WP)
					  da->warnings|=DAW_IO;            // I/O command
				  // Win32 programs usually try to keep stack dword-aligned, so INC ESP
				  // (44) and DEC ESP (4C) usually don't appear in real code. Also check for
				  // ADD ESP,imm and SUB ESP,imm (81,C4,imm32; 83,C4,imm8; 81,EC,imm32;
				  // 83,EC,imm8).
				  if (cmd[0]==0x44 || cmd[0]==0x4C ||
					  (size>=3 && (cmd[0]==0x81 || cmd[0]==0x83) &&
					  (cmd[1]==0xC4 || cmd[1]==0xEC) && (cmd[2] & 0x03)!=0)
					  ) {
						  da->warnings|=DAW_STACK;
						  da->cmdtype|=C_RARE; };
						  // Warn also on MOV SEG,... (8E...). Win32 works in flat mode.
						  if (cmd[0]==0x8E)
							  da->warnings|=DAW_SEGMENT;
						  // If opcode is 2-byte, adjust command.
						  if (pd->len==2) {
							  if (size==0) da->error=DAE_CROSS;
							  else {
								  if (mode>=DISASM_FILE)
									  ndump+=sprintf(da->dump+ndump,"%02X",(BYTE)*cmd);
								  cmd++; srcip++; size--;
							  }; };
							  if (size==0) da->error=DAE_CROSS;
							  // Some commands either feature non-standard data size or have bit which
							  // allowes to select data size.
							  if ((pd->bits & WW)!=0 && (*cmd & WW)==0)
								  datasize=1;                      // Bit W in command set to 0
							  else if ((pd->bits & W3)!=0 && (*cmd & W3)==0)
								  datasize=1;                      // Another position of bit W
							  else if ((pd->bits & FF)!=0)
								  datasize=2;                      // Forced word (2-byte) size
							  // Some commands either have mnemonics which depend on data size (8/16 bits
							  // or 32 bits, like CWD/CDQ), or have several different mnemonics (like
							  // JNZ/JNE). First case is marked by either '&' (mnemonic depends on
							  // operand size) or '$' (depends on address size). In the second case,
							  // there is no special marker and disassembler selects main mnemonic.
							  if (mode>=DISASM_FILE) {
								  if (pd->name[0]=='&') mnemosize=datasize;
								  else if (pd->name[0]=='$') mnemosize=addrsize;
								  else mnemosize=0;
								  if (mnemosize!=0) {
									  for (i=0,j=1; pd->name[j]!='\0'; j++) {
										  if (pd->name[j]==':') {      // Separator between 16/32 mnemonics
											  if (mnemosize==4) i=0;
											  else break; }
										  else if (pd->name[j]=='*') { // Substitute by 'W', 'D' or none
											  if (mnemosize==4 && sizesens!=2) name[i++]='D';
											  else if (mnemosize!=4 && sizesens!=0) name[i++]='W'; }
										  else name[i++]=pd->name[j];
									  };
									  name[i]='\0'; }
								  else {
									  strcpy(name,pd->name);
									  for (i=0; name[i]!='\0'; i++) {
										  if (name[i]==',') {          // Use main mnemonic
											  name[i]='\0'; break;
										  };
									  };
								  };
								  if (repprefix!=0 && tabarguments) {
									  for (i=0; name[i]!='\0' && name[i]!=' '; i++)
										  da->result[nresult++]=name[i];
									  if (name[i]==' ') {
										  da->result[nresult++]=' '; i++; };
										  while (nresult<8) da->result[nresult++]=' ';
										  for ( ; name[i]!='\0'; i++)
											  da->result[nresult++]=name[i];
										  ; }
								  else
									  nresult+=sprintf(da->result+nresult,"%s",name);
								  if (lowercase) strlwr(da->result);
							  };
							  // Decode operands (explicit - encoded in command, implicit - present in
							  // mmemonic or assumed - used or modified by command). Assumed operands
							  // must stay after all explicit and implicit operands. Up to 3 operands
							  // are allowed.
							  for (operand=0; operand<3; operand++) {
								  if (da->error) break;            // Error - no sense to continue
								  // If command contains both source and destination, one usually must not
								  // decode destination to comment because it will be overwritten on the
								  // next step. Global addcomment takes care of this. Decoding routines,
								  // however, may ignore this flag.
								  if (operand==0 && pd->arg2!=NNN && pd->arg2<PSEUDOOP)
									  addcomment=0;
								  else
									  addcomment=1;
								  // Get type of next argument.
								  if (operand==0) arg=pd->arg1;
								  else if (operand==1) arg=pd->arg2;
								  else arg=pd->arg3;
								  if (arg==NNN) break;             // No more operands
								  // Arguments with arg>=PSEUDOOP are assumed operands and are not
								  // displayed in disassembled result, so they require no delimiter.
								  if ((mode>=DISASM_FILE) && arg<PSEUDOOP) {
									  if (operand==0) {
										  da->result[nresult++]=' ';
										  if (tabarguments) {
											  while (nresult<10) da->result[nresult++]=' ';
										  }; }
									  else {
										  da->result[nresult++]=',';
										  if (extraspace) da->result[nresult++]=' ';
									  };
								  };
								  // Decode, analyse and comment next operand of the command.
								  switch (arg) {
	  case REG:                      // Integer register in Reg field
		  if (size<2) da->error=DAE_CROSS;
		  else DecodeRG(cmd[1]>>3,datasize,REG);
		  hasrm=1; break;
	  case RCM:                      // Integer register in command byte
		  DecodeRG(cmd[0],datasize,RCM); break;
	  case RG4:                      // Integer 4-byte register in Reg field
		  if (size<2) da->error=DAE_CROSS;
		  else DecodeRG(cmd[1]>>3,4,RG4);
		  hasrm=1; break;
	  case RAC:                      // Accumulator (AL/AX/EAX, implicit)
		  DecodeRG(REG_EAX,datasize,RAC); break;
	  case RAX:                      // AX (2-byte, implicit)
		  DecodeRG(REG_EAX,2,RAX); break;
	  case RDX:                      // DX (16-bit implicit port address)
		  DecodeRG(REG_EDX,2,RDX); break;
	  case RCL:                      // Implicit CL register (for shifts)
		  DecodeRG(REG_ECX,1,RCL); break;
	  case RS0:                      // Top of FPU stack (ST(0))
		  DecodeST(0,0); break;
	  case RST:                      // FPU register (ST(i)) in command byte
		  DecodeST(cmd[0],0); break;
	  case RMX:                      // MMX register MMx
		  if (size<2) da->error=DAE_CROSS;
		  else DecodeMX(cmd[1]>>3);
		  hasrm=1; break;
	  case R3D:                      // 3DNow! register MMx
		  if (size<2) da->error=DAE_CROSS;
		  else DecodeNR(cmd[1]>>3);
		  hasrm=1; break;
	  case MRG:                      // Memory/register in ModRM byte
	  case MRJ:                      // Memory/reg in ModRM as JUMP target
	  case MR1:                      // 1-byte memory/register in ModRM byte
	  case MR2:                      // 2-byte memory/register in ModRM byte
	  case MR4:                      // 4-byte memory/register in ModRM byte
	  case MR8:                      // 8-byte memory/MMX register in ModRM
	  case MRD:                      // 8-byte memory/3DNow! register in ModRM
	  case MMA:                      // Memory address in ModRM byte for LEA
	  case MML:                      // Memory in ModRM byte (for LES)
	  case MM6:                      // Memory in ModRm (6-byte descriptor)
	  case MMB:                      // Two adjacent memory locations (BOUND)
	  case MD2:                      // Memory in ModRM byte (16-bit integer)
	  case MB2:                      // Memory in ModRM byte (16-bit binary)
	  case MD4:                      // Memory in ModRM byte (32-bit integer)
	  case MD8:                      // Memory in ModRM byte (64-bit integer)
	  case MDA:                      // Memory in ModRM byte (80-bit BCD)
	  case MF4:                      // Memory in ModRM byte (32-bit float)
	  case MF8:                      // Memory in ModRM byte (64-bit float)
	  case MFA:                      // Memory in ModRM byte (80-bit float)
	  case MFE:                      // Memory in ModRM byte (FPU environment)
	  case MFS:                      // Memory in ModRM byte (FPU state)
	  case MFX:                      // Memory in ModRM byte (ext. FPU state)
		  DecodeMR(arg); break;
	  case MMS:                      // Memory in ModRM byte (as SEG:OFFS)
		  DecodeMR(arg);
		  da->warnings|=DAW_FARADDR; break;
	  case RR4:                      // 4-byte memory/register (register only)
	  case RR8:                      // 8-byte MMX register only in ModRM
	  case RRD:                      // 8-byte memory/3DNow! (register only)
		  if ((cmd[1] & 0xC0)!=0xC0) softerror=DAE_REGISTER;
		  DecodeMR(arg); break;
	  case MSO:                      // Source in string op's ([ESI])
		  DecodeSO(); break;
	  case MDE:                      // Destination in string op's ([EDI])
		  DecodeDE(); break;
	  case MXL:                      // XLAT operand ([EBX+AL])
		  DecodeXL(); break;
	  case IMM:                      // Immediate data (8 or 16/32)
	  case IMU:                      // Immediate unsigned data (8 or 16/32)
		  if ((pd->bits & SS)!=0 && (*cmd & 0x02)!=0)
			  DecodeIM(1,datasize,arg);
		  else
			  DecodeIM(datasize,0,arg);
		  break;
	  case VXD:                      // VxD service (32-bit only)
		  DecodeVX(); break;
	  case IMX:                      // Immediate sign-extendable byte
		  DecodeIM(1,datasize,arg); break;
	  case C01:                      // Implicit constant 1 (for shifts)
		  DecodeC1(); break;
	  case IMS:                      // Immediate byte (for shifts)
	  case IM1:                      // Immediate byte
		  DecodeIM(1,0,arg); break;
	  case IM2:                      // Immediate word (ENTER/RET)
		  DecodeIM(2,0,arg);
		  if ((da->immconst & 0x03)!=0) da->warnings|=DAW_STACK;
		  break;
	  case IMA:                      // Immediate absolute near data address
		  DecodeIA(); break;
	  case JOB:                      // Immediate byte offset (for jumps)
		  DecodeRJ(1,srcip+2); break;
	  case JOW:                      // Immediate full offset (for jumps)
		  DecodeRJ(datasize,srcip+datasize+1); break;
	  case JMF:                      // Immediate absolute far jump/call addr
		  DecodeJF();
		  da->warnings|=DAW_FARADDR; break;
	  case SGM:                      // Segment register in ModRM byte
		  if (size<2) da->error=DAE_CROSS;
		  DecodeSG(cmd[1]>>3); hasrm=1; break;
	  case SCM:                      // Segment register in command byte
		  DecodeSG(cmd[0]>>3);
		  if ((da->cmdtype & C_TYPEMASK)==C_POP) da->warnings|=DAW_SEGMENT;
		  break;
	  case CRX:                      // Control register CRx
		  if ((cmd[1] & 0xC0)!=0xC0) da->error=DAE_REGISTER;
		  DecodeCR(cmd[1]); break;
	  case DRX:                      // Debug register DRx
		  if ((cmd[1] & 0xC0)!=0xC0) da->error=DAE_REGISTER;
		  DecodeDR(cmd[1]); break;
	  case PRN:                      // Near return address (pseudooperand)
		  break;
	  case PRF:                      // Far return address (pseudooperand)
		  da->warnings|=DAW_FARADDR; break;
	  case PAC:                      // Accumulator (AL/AX/EAX, pseudooperand)
		  DecodeRG(REG_EAX,datasize,PAC); break;
	  case PAH:                      // AH (in LAHF/SAHF, pseudooperand)
	  case PFL:                      // Lower byte of flags (pseudooperand)
		  break;
	  case PS0:                      // Top of FPU stack (pseudooperand)
		  DecodeST(0,1); break;
	  case PS1:                      // ST(1) (pseudooperand)
		  DecodeST(1,1); break;
	  case PCX:                      // CX/ECX (pseudooperand)
		  DecodeRG(REG_ECX,cxsize,PCX); break;
	  case PDI:                      // EDI (pseudooperand in MMX extentions)
		  DecodeRG(REG_EDI,4,PDI); break;
	  default:
		  da->error=DAE_INTERN;        // Unknown argument type
		  break;
								  };
							  };
							  // Check whether command may possibly contain fixups.
							  if (pfixup!=NULL && da->fixupsize>0)
								  da->fixupoffset=pfixup-src;
							  // Segment prefix and address size prefix are superfluous for command which
							  // does not access memory. If this the case, mark command as rare to help
							  // in analysis.
							  if (da->memtype==DEC_UNKNOWN &&
								  (segprefix!=SEG_UNDEF || (addrsize!=4 && pd->name[0]!='$'))
								  ) {
									  da->warnings|=DAW_PREFIX;
									  da->cmdtype|=C_RARE; };
									  // 16-bit addressing is rare in 32-bit programs. If this is the case,
									  // mark command as rare to help in analysis.
									  if (addrsize!=4) da->cmdtype|=C_RARE;
			  };
			  // Suffix of 3DNow! command is accounted best by assuming it immediate byte
			  // constant.
			  if (is3dnow) {
				  if (immsize!=0) da->error=DAE_BADCMD;
				  else immsize=1; };
				  // Right or wrong, command decoded. Now dump it.
				  if (da->error!=0) {                  // Hard error in command detected
					  if (mode>=DISASM_FILE)
						  nresult=sprintf(da->result,"???");
					  if (da->error==DAE_BADCMD &&
						  (*cmd==0x0F || *cmd==0xFF) && size>0
						  ) {
							  if (mode>=DISASM_FILE) ndump+=sprintf(da->dump+ndump,"%02X",(BYTE)*cmd);
							  cmd++; size--; };
							  if (size>0) {
								  if (mode>=DISASM_FILE) ndump+=sprintf(da->dump+ndump,"%02X",(BYTE)*cmd);
								  cmd++; size--;
							  }; }
				  else {                               // No hard error, dump command
					  if (mode>=DISASM_FILE) {
						  ndump+=sprintf(da->dump+ndump,"%02X",(BYTE)*cmd++);
						  if (hasrm) ndump+=sprintf(da->dump+ndump,"%02X",(BYTE)*cmd++);
						  if (hassib) ndump+=sprintf(da->dump+ndump,"%02X",(BYTE)*cmd++);
						  if (dispsize!=0) {
							  da->dump[ndump++]=' ';
							  for (i=0; i<dispsize; i++) {
								  ndump+=sprintf(da->dump+ndump,"%02X",(BYTE)*cmd++);
							  };
						  };
						  if (immsize!=0) {
							  da->dump[ndump++]=' ';
							  for (i=0; i<immsize; i++) {
								  ndump+=sprintf(da->dump+ndump,"%02X",(BYTE)*cmd++);
							  };
						  };
					  }
					  else
						  cmd+=1+hasrm+hassib+dispsize+immsize;
					  size-=1+hasrm+hassib+dispsize+immsize;
				  };
				  // Check that command is not a dangerous one.
				  if (mode>=DISASM_DATA) {
					  for (pdan=dangerous; pdan->mask!=0; pdan++) {
						  if (((code^pdan->code) & pdan->mask)!=0)
							  continue;
						  if (pdan->type==C_DANGERLOCK && lockprefix==0)
							  break;                         // Command harmless without LOCK prefix
						  if (iswindowsnt && pdan->type==C_DANGER95)
							  break;                         // Command harmless under Windows NT
						  // Dangerous command!
						  if (pdan->type==C_DANGER95) da->warnings|=DAW_DANGER95;
						  else da->warnings|=DAW_DANGEROUS;
						  break;
					  };
				  };
				  if (da->error==0 && softerror!=0)
					  da->error=softerror;               // Error, but still display command
				  if (mode>=DISASM_FILE) {
					  if (da->error!=DAE_NOERR) switch (da->error) {
	  case DAE_CROSS:
		  strcpy(da->comment,"Command crosses end of memory block"); break;
	  case DAE_BADCMD:
		  strcpy(da->comment,"Unknown command"); break;
	  case DAE_BADSEG:
		  strcpy(da->comment,"Undefined segment register"); break;
	  case DAE_MEMORY:
		  strcpy(da->comment,"Illegal use of register"); break;
	  case DAE_REGISTER:
		  strcpy(da->comment,"Memory address not allowed"); break;
	  case DAE_INTERN:
		  strcpy(da->comment,"Internal OLLYDBG error"); break;
	  default:
		  strcpy(da->comment,"Unknown error");
		  break; }
					  else if ((da->warnings & DAW_PRIV)!=0 && privileged==0)
						  strcpy(da->comment,"Privileged command");
					  else if ((da->warnings & DAW_IO)!=0 && iocommand==0)
						  strcpy(da->comment,"I/O command");
					  else if ((da->warnings & DAW_FARADDR)!=0 && farcalls==0) {
						  if ((da->cmdtype & C_TYPEMASK)==C_JMP)
							  strcpy(da->comment,"Far jump");
						  else if ((da->cmdtype & C_TYPEMASK)==C_CAL)
							  strcpy(da->comment,"Far call");
						  else if ((da->cmdtype & C_TYPEMASK)==C_RET)
							  strcpy(da->comment,"Far return");
						  ; }
					  else if ((da->warnings & DAW_SEGMENT)!=0 && farcalls==0)
						  strcpy(da->comment,"Modification of segment register");
					  else if ((da->warnings & DAW_SHIFT)!=0 && badshift==0)
						  strcpy(da->comment,"Shift constant out of range 1..31");
					  else if ((da->warnings & DAW_PREFIX)!=0 && extraprefix==0)
						  strcpy(da->comment,"Superfluous prefix");
					  else if ((da->warnings & DAW_LOCK)!=0 && lockedbus==0)
						  strcpy(da->comment,"LOCK prefix");
					  else if ((da->warnings & DAW_STACK)!=0 && stackalign==0)
						  strcpy(da->comment,"Unaligned stack operation");
					  ;
				  };
				  return (srcsize-size);               // Returns number of recognized bytes
};

#pragma warning(default:4996)  
#pragma warning(default:4244)