/*		compact.h - types and macro definition cvpack
 *
 */

#define STRICT

#define NOMINMAX		       // windef.h
#define NOGDI			       // wingdi.h
#define NOIME			       // ime.h
#define NOUSER			       // winuser.h
#define NOHELP
#define NOPROFILER
#define NOSYSPARAMSINFO
#define NONLS			       // winnls.h
#define NOSERVICE		       // winsvc.h
#include "windows.h"

#if __cplusplus
#define INLINE inline
#else
#define INLINE __inline
#endif

#include <assert.h>
#include <fcntl.h>
#include <io.h>
#include <limits.h>
#include <malloc.h>
#include <process.h>
#include <share.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <tchar.h>
#include <sys\stat.h>
#include <sys\types.h>

#include "bufio.h"
#include "fileio.h"

#define _vmhnd_t unsigned char *

// ddbdumps.c

#if DBG //{
extern char DbArray[50];
void DDHeapUsage(char *);
void * __cdecl TrapMalloc(size_t);
#else //}{
#define DDHeapUsage(Modulename)
#define TrapMalloc(size)			malloc(size)
#endif

#include "cvinfo.h"
#include "cvtdef.h"
#include "cvexefmt.h"
#include "vbuf.h"
#include "defines.h"
#include "padmacro.h"


// define DASSERT macro
#if DBG
#define DASSERT(ex) assert(ex)
#else
#define DASSERT(ex)
#endif
typedef unsigned char	uchar;
typedef unsigned short	ushort;
typedef unsigned long	ulong;
typedef unsigned int	uint;
typedef uint			bool_t;

typedef ulong uoff32_t;
typedef  long  off32_t;
typedef ushort uoff16_t;
typedef  short	off16_t;

// message ordinals

#include "msg.h"

typedef ushort (*LPFNHASH) (SYMPTR, ulong *, ushort *, ushort *, ulong *, ushort);


#define MAXCDF			254 // The maximum number of code segments to allow
							// in a single module.
#define MAXSTRLEN		256 // The maximum string length to convert
#define MAXNUMERICLEN	 18 // Longest Numeric possible (LF_REAL128)
#define GTYPE_INC		512 // number of type string pointers per buffer
#define POOLSIZE		 32
#define POOL2SIZE		900
#define RECURSE_INC 	  5
#define ZEROARGTYPE  0xFFFF // Magic type index that causes a LF_ARGLIST

#if DBG
#define BreakOnIndex(a) IndexBreak (a)
#else
#define BreakOnIndex(a)
#endif


#if defined (STATS)
#define COUNTER(a)	long a;
#define COUNT(a)	a++;
#else
#define COUNTER(a)
#define COUNT(a)
#endif

#define TRUE		1
#define FALSE		0

#define LOCAL


typedef enum FWD_t {
	FWD_none,
	FWD_local,
	FWD_global,
	FWD_globalfwd
} FWD_t;


#define cbAlign 	0x1000
#define cbTypeAlign 0xC000

//	This hash table is used to hash local structures, class, unions
//	and enums so that they can be quickly found for satisfying forward
//	references.  The hash is the sum of characters in the name.


typedef struct HSFWD {
	uchar	   *pName;
	TYPPTR	   pType;
	CV_typ_t	index;
	ushort		SatisfyFwdRef:1;
	ushort		WarnIsOut:1;
	struct		HSFWD *Next;
} HSFWD;

#define HASH_FWD			512 	// hash size for forward definition


typedef struct TypeIndexEntry {
	uchar	   *TypeString;
	CV_typ_t	CompactedIndex;
	CV_typ_t	ForwardIndex;
	ushort		Count;				// count of recursive index offsets
	ushort		Hash;
	union {
		ushort *IndexString;
		uchar	Index[RECURSE_INC];
	} IndexUnion;					// offsets of recursive indices
	union {
		uchar	GlobalIndex;
		uchar  *GlobalIndexString;
	};
	struct {
		ushort	IsBeingMatched :1;	// being matched
		ushort	IsMatched	   :1;
		ushort	IsInserted	   :1;	// in string hash table
		ushort	IsMalloced	   :1;	// allocated string?
		ushort	IsPool		   :1;	// memory is allocated from pool one
		ushort	IsPool2 	   :1;	// memory is allocated from pool two
		ushort	IsBeingDone    :1;	// in the process?
		ushort	IsDone		   :1;	// done, not inserted
		ushort	LargeList	   :1;	// list
		ushort	WasSkipped	   :1;	// was skipped by LF_SKIP record
		ushort	IsNewFormat    :1;	// string is in C7 fromat
		ushort	IsPreComp	   :1;	// is from precompiled types table
		ushort	IsForward	   :1;	// true if in progress forward ref
		ushort	IsBeingFreed   :1;	// true if allocated strings being freed
		ushort	InputWasFwd    :1;	// was a forward decl UDT on input
		ushort	IsParameter    :1;	// true if OLF_PARAMETER (compacted index
									// is referenced index
	} flags;
} TENTRY;
extern	TENTRY *ModuleIndexTable;

typedef enum GPS_t {
	GPS_intable,					// symbol is in the global symbol table
	GPS_added,						// symbol added to the global table
	GPS_noadd						// symbol in table but different
} GPS_t;




/* get the length of a type string */

#define 	LENGTH(type)		(*(ushort UNALIGNED *)(type + 1))
#define 	C7LENGTH(type)		(*(ushort *)(type))
#define 	LNGTHSZ 2				// The size of the length field
#define 	RECTYPSZ 2				// The size of the record type field
#define 	MAXC6NUMERICGROWTH 1	// Maximum growth to convert
									// C6 Numeric to C7 Numeric
#define 	MAXPAD 3				// Maximum number of bytes to pad to 4 byte boundry




// definition of in core list of modules

typedef struct ModuleListType {
	ushort		ModuleIndex;
	char	   *pName;				// length of module name
	ulong		signature;			// precompiled types signature
	ulong		ModulesAddr;
	ulong		ModuleSize;
	ulong		SymbolsAddr;
	ulong		SymbolSize;
	ulong		SrcLnAddr;
	ulong		SrcLnSize;
	ulong		PreCompAddr;
	ushort		PreCompSize;
	struct		ModuleListType *next;
} MOD;
typedef MOD *PMOD;


typedef struct PACKDATA {
	ushort	iMod;					// index of module to be packed
	long	iDir;					// index of beginning directory entry
	PMOD	pMod;					// pointer to module entry
} PACKDATA;




// externs for global variables

extern int		exefile;			   // the .exe file
extern bool_t	verifyDebug;		   // verify debug data correctness
extern bool_t	logo;				   // print logo and compression numbers
extern bool_t	verbose;			   // print packer stats at end of pack
extern bool_t	strip;				   // just strip the cv info
extern bool_t	fDelete;			   // delete symbols and types
extern bool_t	NeedsBanner;		   // false if banner already printed
extern bool_t	PackingPreComp; 	   // true if packing a precompiled types file
extern bool_t	IsMFCobol;			   // True if packing MF COBOL

extern ulong	InitialTypeInfoSize;
extern ulong	InitialSymInfoSize;
extern ulong	FinalSymInfoSize;
	   ulong	cSST;				   // count of subsection tables
extern uchar	fLinearExe;
extern ushort	cMod;				   // count of number of modules in file
	   ushort	cTypeSeg;			   // count of number of type segments
	   ushort	iTypeSeg;			   // index into type segment pointer array
	   uchar	**pTypeSeg; 		   // pointer to array of type segment pointers
	   size_t	maxPublicsSub;		   // maximum publics subsection size
	   size_t	maxSymbolsSub;		   // maximum symbols subsection size
	   size_t	maxSrcLnSub;		   // maximum symbols subsection size
	   size_t	maxModSub;			   // maximum symbols subsection size
	   ulong	maxTypes;			   // maximum types subsection size
	   ulong	maxPublics; 		   // maximum publics subsection size
	   ulong	maxSymbols; 		   // maximum symbols subsection size
	   ulong	maxSrcLn;			   // maximum SrcLnSeg/sstModule subsection size
	   ulong	maxMod; 			   // maximum publics subsection size
	   uchar	*pTypes;			   // pointer to types table read buffer
	   uchar	*pPublics;			   // pointer to publics table read buffer
	   uchar	*pSymbols;			   // pointer to symbols table read buffer
	   uchar	*pSrcLn;			   // pointer to sourcelins table read buffer
	   oldsmd	*pSSTMOD;			   // pointer to sourcelins table read buffer
extern uchar	**pGType[]; 		   // array of pointers to global type pointers
	   PMOD 	pCurMod;			   // pointer to current module being packed
	   PMOD 	pRefMod;			   // pointer to referenced module

extern VBuf 		 SymBuf;
extern VBuf 		 TypeBuf;
extern OMFDirEntry	 *pDir; 		   // directory read from exe
extern _vmhnd_t 	 Libraries;
extern _vmhnd_t 	 SegMap;
extern _vmhnd_t 	 SegName;
	   _vmhnd_t 	 FileIndex;
extern ulong		 LibSize;
extern ulong		 SegMapSize;
extern ulong		 SegNameSize;
       ulong		 FileIndexSize;
	   long 		 filepos;
	   long 		 lfoDir;
	   long 		 lfoBase;
extern char 		 *ModAddr;
extern ushort		 cSeg;
extern ushort		 segnum[MAXCDF];
extern OMFDirHeader  DirHead;
extern PACKDATA 	 *PackOrder;
extern CV_typ_t 	 maxPreComp;	   // maximum precompiled type for this module
extern PMOD 		 ModuleList;
extern char 		 *pDbgFile;

/*	link_* - define i/o thunks for the case when cvpack is embedded in linker.
 */
#ifdef CVPACKLIB
int  __cdecl link_chsize(int,		   long);
int  __cdecl link_close (int);
void __cdecl link_exit	(int);
long __cdecl link_lseek (int,		   long,		 int);
int  __cdecl link_open	(const char *, int, 		 ...);
int  __cdecl link_read	(int,		   void *,		 unsigned int);
long __cdecl link_tell	(int);
int  __cdecl link_write (int,		   const void *, unsigned int);
#else
#define link_chsize 	FileChSize
#define link_close(x)	FileClose ( x, TRUE )
#define link_lseek		FileSeek
#define link_open		FileOpen
#define link_read		FileRead
#define link_tell		FileTell
#define link_write		FileWrite
#define link_exit		exit
#endif

//			compact6.c

CV_typ_t	_fastcall C6GetCompactedIndex (CV_typ_t);
CV_typ_t	_fastcall C6GetCompactedIndexRecur (CV_typ_t);

//			compact7.c

void		IndexBreak (CV_typ_t);
CV_typ_t	_fastcall C7GetCompactedIndex (CV_typ_t);
CV_typ_t	_fastcall CompactList (CV_typ_t, ushort);
uchar		_fastcall CompactPtr (TENTRY *);
void		PackPreComp (PMOD);
void _fastcall AddFwdRef(CV_typ_t OldIndex, HSFWD *pHash);
void _fastcall PickUpFwdRefs(void);

//			error.c

void		ErrorExit(unsigned, const char *, const char *);
const char *FormatMod(PMOD);
void		Warn(unsigned, const char *, const char *);



//			engine.c

bool_t		CompactOneModule (ushort);
uchar	   *GetSymString (ushort);
bool_t		SegmentPresent (ushort);
extern		ulong		ulCVTypeSignature; // The signature from the modules type segment
extern		ushort		usCurFirstNonPrim; // The current first non primitive type index


//			module.c

void		FixupExeFile (void);
OMFDirEntry *GetNextModuleEntry (OMFDirEntry *);
void		ReadDir (void);


//			obsolete.c

void		ConvertObsolete (ushort);


//			recurse.c


#if 1 // { GTW: inlined parts of this function.

bool_t		_fastcall IdenticalTree_(TENTRY *, CV_typ_t, TYPPTR, CV_typ_t);

#else

bool_t		IdenticalTree (TENTRY *, CV_typ_t, TYPPTR, CV_typ_t);

#endif

CV_typ_t	_fastcall AddRecursiveType (CV_typ_t);



//			tables.c

ushort		AddrHash (SYMPTR, ushort *, ushort *, ushort);
ushort		AddSearchSym (uchar *, ushort);
void		_fastcall AddTypeToStringTable (uchar *, CV_typ_t);
void		_fastcall AddTypeToTypeTable (TENTRY *);
void		CleanUpTables (void);
ushort		ComDat (uchar *);
void		C7ReadTypes (ulong, bool_t);
void		C6ReadTypes (uchar *, ulong);
void		DoDerivationList (CV_typ_t, CV_typ_t);
FWD_t		_fastcall FindFwdRef (TENTRY *, HSFWD **, bool_t);
void		ClearHashFwdLocal();
void		ReadTDB(char *szTdbToRead);
extern		int TDBStayedResident;
extern		int NeedToClearTDB;
extern	void	InitModTypeTable (void);

#if 1 // { GTW: inline FreeAllocStrings guard.

void		FreeAllocStrings_ (TENTRY *);

#else

void		FreeAllocStrings (TENTRY *);

#endif // }

void		FreeStrings (CV_typ_t);
INLINE TENTRY  *GetRawTypeEntry (CV_typ_t);
TENTRY	   *GetTypeEntry (CV_typ_t, CV_typ_t *);
CV_typ_t	GetRecursiveIndex (TENTRY *, CV_typ_t);
void		InitializeTables (void);
void		_fastcall InsertIntoTypeSegment (TENTRY *);
bool_t		IsFwdRef (TYPPTR);
bool_t		LinkScope (uchar *, ulong);
void		_fastcall MatchIndex (TENTRY *);
GPS_t		_fastcall PackSymbol (SYMPTR, LPFNHASH);
GPS_t		PackPublic (SYMPTR, LPFNHASH);
void		PrepareGlobalTypeTable (void);
bool_t		SegmentPresent (ushort);
ushort		DWordXorShift (SYMPTR, ulong *, ushort *, ushort *, ulong *, ushort);
void		WriteStaticSym (OMFDirEntry *, long);
#define HASHFUNC DWordXorShift
void		WriteGlobalSym (OMFDirEntry *, long);
void		WritePublics (OMFDirEntry *, long);
extern		CV_typ_t MaxIndex;				// Maximum index for module
extern		CV_typ_t PreviousMaxIndex;
extern		HSFWD **HTLocalFwd;
extern bool_t NoMoTypes;


//			stack.c

#if 0		// { GTW inlined.

void		SetRecursiveRoot (ushort);

void		Push (ushort);
void		Pop (void);

#endif		// }

extern CV_typ_t RecursiveRoot;





//			utils.c

ushort		getshortvalue (uchar **);
short		SkipNumericLeaf (uchar *);
void	   *CAlloc (uint);
void	   *Alloc (uint);
void	   *PoolAlloc (void);
void		PoolFree (void *);
void	   *Pool2Alloc (void);
void		Pool2Free (void *);
void	   *NoErrorRealloc (void *, uint);
uchar	   *GetScratchString (uint);
ulong		C6GetLWordFromNumeric (uchar **, ushort *);

#if 1		// { GTW: inline version.

ushort		C7SizeOfNumeric_(uchar *);

#else		// }{

ushort		C7SizeOfNumeric (uchar *);

#endif

ushort		C7SizeOfNumeric (uchar *);

ushort		C7StoreLWordAsNumeric (uchar *, ulong);

//			utils6.c

ushort		C6GetWordFromNumeric (uchar **, ushort *);
ulong		C6GetLWordFromNumeric (uchar **, ushort *);
ushort		ConvertNumeric (uchar **, uchar **);


//			symbols6.c

void		C6CalcNewSizeOfSymbols (uchar *, ulong);
void		C6RewriteAndFixupSymbols (uchar *, OMFDirEntry *, char *, PMOD);
ushort		C6CnvtSymbol (uchar *pC7Sym, uchar *pC6Sym);

//			symbols7.c

void		C7CalcNewSizeOfSymbols (uchar *, ulong, ushort *, ushort *);
void		C7RewriteAndFixupSymbols (uchar *, OMFDirEntry *, PMOD,
			  ushort *, ushort *);
void		C7RewritePublics (uchar *, OMFDirEntry *);

//			cnvtprim.c

ushort		C6MapPrimitive (ushort);

//			main.c

void		Banner (void);
extern		bool_t	IDEFeedback;
extern		char	*pDbgFilename;		// dbg file name
int OpenOutputFile (char *path, char* pDefExt, int CreateFlag);



//			type7.c

void CheckDouble (TENTRY *);
void DumpLocalList (CV_typ_t);
void DumpGlobalList (CV_typ_t);
void DumpFull (void);
void DumpPartial (void);
void DumpPartialType (CV_typ_t, TYPPTR, bool_t);
void DumpFullType (ushort, TYPPTR, bool_t);

#undef _HEAP_MAXREQ
// _HEAP_MAXREQ should always < 64K, regardless of host environment
#define _HEAP_MAXREQ	0xFFE8

#include "inlines.h"

#pragma warning(4:4124)  // __fastcall with stack checking is inefficient