;
; Program name:NMS File to text
;
;
;commandLine:  N2T.exe nmsfile.nms textfile.txt
;

include definitions.inc


.data
ProgramName	db"NMS to text translator",0

hInstance			HINSTANCE ?
pCommandLineFlags	POINTER ?

BytesReadWrite		DWORD 0

nms				NMSFILE<0, 0, 0, 0, 0, 0, 1, 0, 0>
text				TXTFILE<0, 0, 0, 0>


currentDir		BYTE MAX_PATH dup(0)	;this few I had first as locals but something wasn't right so...
nmsName			BYTE 64 dup(0)
textName			BYTE 64 dup(0)
tempBuffer		BYTE MAX_PATH dup(0)
errorBuffer		BYTE 64 dup(0)

currentOffset		DWORD 0

.code
Main:
USES ebx, edx, esi, edi

		call GetModuleHandle, NULL
		mov	hInstance, eax
		call	GetCurrentDirectory, MAX_PATH, offset currentDir
		call	GetCommandLine

;get over file execution path ( '"c:\blab\bla\n2t.exe" variable1 variable2' )
@Loop1:
		inc	eax		;over first ' " '
		cmp	byte ptr [eax], '"'
		jne	@Loop1
		inc	eax				;over second ' " '

;test if user set any variable
		mov	cl, byte ptr[eax]
		test	cl, cl		;is there anything
		jz	@ERROR_CommandLine

		mov	ebx, offset nmsName		;offset to buffer
;find first variable
@Loop2:
		inc	eax					;over 1st space in command line ('...\n2t.exe" nmsfile.nms textfile.txt')
		cmp	byte ptr [eax], ' '		;is there a next space
		je	@Loop2

		mov	[nms.pFileName], ebx
;strCpy( nmsName, nmsNameInCommandLine)
@Loop3:
		mov	cl, byte ptr [eax]
		cmp	cl, ' '				;is it over nmsName.nms
		je	@OverNmsName
		cmp	cl, NULL
		je	@OnlyNmsNameDefined
		mov	byte ptr [ebx], cl
		inc	eax
		inc	ebx
		jmp	@Loop3
@OverNmsName:
		mov	byte ptr [ebx], NULL	;zero ended string

;find second variable
		mov	ebx, offset textName	;offset to buffer
@Loop4:
		inc	eax					;over 1st space
		cmp	byte ptr [eax], ' '
		je	@Loop4

		mov	[text.pFileName], ebx
;strCpy( txtName, txtNameInCommandLine)
@Loop5:
		mov	cl, byte ptr [eax]
		cmp	cl, ' '
		je	@OverTextName
		cmp	cl, NULL
		je	@OverTextName
		mov	byte ptr [ebx], cl
		inc	eax
		inc	ebx
		jmp	@Loop5
@OverTextName:
		mov	byte ptr [ebx], NULL	;zero ended string
		jmp	@MakeDirToNMSFile

;if we ended here than only the first variable was set =>
; =>copy nmsName to txtBuffer and change extension to .txt
;
;ebx points to the end of NmsName buffer
@OnlyNmsNameDefined:
		mov	byte ptr [ebx], NULL	;zero ended string
		mov	eax, offset nmsName
		mov	ebx, offset textName
		mov	[text.pFileName], ebx
@Loop6:
		mov	cl, byte ptr [eax]
		cmp	cl, '.'				;is it a dot
		je	@FoundADot
		cmp	cl, NULL				;check if variable1 was defined and if commandLine had space at the end, but no variable1  "...\n2t ".
		je	@ERROR_CommandLine		;no dot found
		mov	byte ptr [ebx], cl
		inc	eax
		inc	ebx
		jmp	@Loop6
@FoundADot:
		mov	dword ptr [ebx], 'txt.'		;3of4 we'll get time penalty (we're not dword alligned,
									;but still better than 8 commands)
		mov	byte ptr [ebx+4], NULL

@MakeDirToNMSFile:
;check if we really have variable2 defined
;Error could occur if commandLine had space at the end, but no variable2  "...\n2t var1.nms " 
		mov	ebx, [text.pFileName]
		cmp	byte ptr [ebx], NULL
		jz	@OnlyNmsNameDefined

;Make CurrentDir\nmsName.nms
		mov	ebx, offset currentDir	;from
		xor	ecx, ecx
		mov	esi, ebx				;source
		mov	edi, offset tempBuffer	;to
;get the length of currentDir path
@Loop7:
		cmp	byte ptr [ebx], NULL	;are we at the end
		je	@CurrentDirAtTheEnd
		inc	ecx
		inc	ebx
		jmp	@Loop7
;strCpy(tempBuffer, currentDir);
@CurrentDirAtTheEnd:
		cld
		repnz movsb

		mov	ebx, [nms.pFileName]	;source
;strCat(tempBuffer, "\\");
		mov	byte ptr [edi], '\'
		inc	edi

		mov	esi, ebx				;source
		xor	ecx, ecx
;get the length of the nmsName
@Loop8:
		cmp	byte ptr [ebx], NULL	;are we at the end
		je	@NmsNameAtTheEnd
		inc	ecx
		inc	ebx
		jmp	@Loop8
;strCat(tempBuffer, nmsName);
@NmsNameAtTheEnd:
		inc	ecx					;copy zero byte too
		cld
		repnz movsb


;--------------------------------------------------------------------------------------------------------------------------
;Open and read nms file
;
		call	CreateFile, offset tempBuffer, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL
		cmp	eax, INVALID_HANDLE_VALUE
		je	@ERROR_FileError
		mov	[nms.hFile], eax

		call	GetFileSize, eax, NULL
		cmp	eax, -1
		je	@ERROR_FileError

		mov	[nms.fileSize], eax		;save variable
		push	NULL					;for ReadFile
		push	offset BytesReadWrite	;for ReadFile
		push	eax					;for ReadFile

		call	GlobalAlloc, GMEM_FIXED, eax
		test	eax, eax
		jz	@ERROR_AllocatingError
		mov	[nms.hMapped], eax
	
		push	eax					;for ReadFile
		push	nms.hFile				;for ReadFile
		call	ReadFile
		test	eax, eax
		setz	bl					;set bl to 1 if eax=NULL

		call	CloseHandle, nms.hFile
		test	eax, eax
		je	@ERROR_FileError

		test	bl, bl				;do we have 1
		jnz	@ERROR_FileReadingError

;--------------------------------------------------------------------------------------------------------------------------
;Read NMS file
;
;
;test if it is a NM32 file
;ESI=startOfNMSFile
		mov	esi, [nms.hMapped]
		cmp	dword ptr [(NM32_HEADER ptr esi).NM32], '23MN'
		jne	@ERROR_FileReadingError
;test if we can get NMDR pointer to structure
		mov	eax, [(NM32_HEADER ptr esi).offNMDR]		;read pNMDR
		add	eax, esi
		cmp	dword ptr [eax], 'RDMN'		;NMDR
		jne	@ERROR_FileReadingError
		mov	[nms.pNMDR], eax

;get memory as easy as it can get
		mov	eax, [nms.fileSize]
		xor	edx, edx
		mov	ecx, 1000h
		div	ecx				;4096
		test	eax, eax
		jnz	@FileSizeMoreThan4096bytes
		mov	eax, 1
@FileSizeMoreThan4096bytes:
		xor	edx, edx
		mov	ecx, 0Ah*01000h		;normal txt file is around 6x size of nms(but just to be shure =>A)
		mul	ecx
		call	GlobalAlloc, GMEM_MOVEABLE, eax	;I set this so that maybe someday I'll make a alloc/realloc function
		test	eax, eax
		je	@ERROR_AllocatingError
		mov	[text.hMemUnlocked], eax
		call	GlobalLock, eax
		test	eax, eax
		je	@ERROR_AllocatingError
		mov	[text.hMapped], eax

;Set NMS2TXT header
.data
TextStart			db"NMS2TXT v0.02 (all numbers are in hex)",13, 10, 13, 10
				db"           file: %s",13,10
				db"        version: %x(major), %x(minor)",13,10
				db"        offNMDR: %x",13,10
				db"   creationTime: %x",13,10
				db" creationNumber: %x",13,10
				db"       fileType: %x",13,10
				db"     fileLength: %x",13,10
				db"       filePath: %s",13,10,13,10
				db"----------------------------------------------------------------------------",13,10
				db"NMDR debug records:",13,10,0
Border			db 13, 10,"----------------------------------------------------------------------------",13,10,0
.code
;EAX=startOfTextBuffer
;ESI=startOfNMSFileBuffer
		lea	ebx, dword ptr [(NM32_HEADER ptr esi).filePath]
		push	ebx						;pointer to string
		push dword ptr [(NM32_HEADER ptr esi).fileLength]
		push dword ptr [(NM32_HEADER ptr esi).fileType]
		push dword ptr [(NM32_HEADER ptr esi).creationNumber]
		push dword ptr [(NM32_HEADER ptr esi).creationTime]
		push dword ptr [(NM32_HEADER ptr esi).offNMDR]
		push dword ptr [(NM32_HEADER ptr esi).verMinor]
		push dword ptr [(NM32_HEADER ptr esi).verMajor]
		push	nms.pFileName
		call	StringComplete, offset TextStart, eax
		add	esp, 09h*04h

;--------------------------------------------------------------------------------------------------------------------------
; NM Debug records:
.data
DebugRecordType	db"   Type: %s  fileOffset: %x  size: %x",13,10,0

sUnknown			db"Unknown type        ",0
sGTYP			db"Global types  (GTYP)",0
sSTTB			db"String tables (STTB)",0
sNMTP			db"NM types      (NMTP)",0
sTYTB			db"Type tables   (TYTB)",0
sHSHT			db"Hash tables   (HSHT)",0
sSYMD			db"Symbol data   (SYMD)",0
sSRCP			db"Source copy   (SRCP)",0
sFPOD			db"              (FPOD)",0

@Table1:
	DWORD offset sUnknown
	DWORD offset sGTYP
	DWORD offset sSTTB
	DWORD offset sNMTP
	DWORD offset sTYTB
	DWORD offset sHSHT
	DWORD offset sSYMD
	DWORD offset sSRCP
	DWORD offset sFPOD
;EndTable
.code
;get pointer to 1st NMDE structure
		mov	[nms.cNMDECurrent], 1				;reset
		mov	ebx, [nms.pNMDR]
		mov	edi, [(NMDR_HEADER ptr ebx).cNMDE]
		add	ebx, SIZE NMDR_HEADER			;now points to NMDE structs
		mov	[nms.cNMDE], edi

;EAX=pointer to 1st free byte in textBuffer
;EBX=current NMDE structure
;ESI=pNMSFileBuffer
;
;show which types are in NMS file
@Type1_Next:
		mov	edi, [nms.cNMDECurrent]
		cmp	edi, dword ptr [nms.cNMDE]
		ja	@Type1_End
		inc	[nms.cNMDECurrent]				;increase
		mov	edi, [(NMDE_S ptr ebx).entryIndex]
		cmp	edi, 8
		ja	@Type1_Unknown
@Type1_Proceed:
		push	dword ptr [(NMDE_S ptr ebx).entryLenght]
		push	dword ptr [(NMDE_S ptr ebx).offEntry]
		cmp	edi, 2						;2=STTB
		je	@Type1_SetSTTB					;if STTB set some variables that we'll need later
@Type1_SetSTTBProceed:
		push	dword ptr [offset @Table1+edi*4]
		call	StringComplete, offset DebugRecordType, eax
		add	esp, 03h*04h
		add	ebx, SIZE NMDE_S
		jmp	@Type1_Next
@Type1_Unknown:
		xor	edi, edi
		jmp	@Type1_Proceed
;find pointers to strings in STTB
@Type1_SetSTTB:
		mov	edx, [(NMDE_S ptr ebx).offEntry]
		add	edx, esi						;add pointer startOfNMSFileBuffer
		mov	ecx, [(STTB_HEADER ptr edx).cNames_STTB]
		add	edx, SIZE STTB_HEADER
		mov	[nms.cNames], ecx
		mov	[nms.pNameOffsets], edx
		lea	edx, [edx+ecx*4]				;pStrings	in memory
		mov	[nms.pStrings], edx
		jmp	@Type1_SetSTTBProceed
@Type1_End:

;--------------------------------------------------------------------------------------------------------------------------
; Explain every type

;EAX=pointer to 1st free byte in textBuffer
;EBX=current NMDE structure
;EDX=entryIndex
;ESI=pNMSFileMapped [nms.hMapped]
;
;define NMS types
		mov	ebx, [nms.pNMDR]
		mov	[nms.cNMDECurrent], 1				;reset
		add	ebx, SIZE NMDR_HEADER				;now points to 1st NMDE structure
@Type2_Next:
		mov	edi, [nms.cNMDECurrent]
		cmp	edi, dword ptr [nms.cNMDE]
		ja	@Type2_End
		inc	[nms.cNMDECurrent]					;increase
		call	StringComplete, offset Border, eax		;Make Border
		mov	edx, [(NMDE_S ptr ebx).entryIndex]
		cmp	edx, 8							;we must save entryIndex
		ja	@Type2_Unknown

@Type2_Proceed:
		mov	ecx, [(NMDE_S ptr ebx).offEntry]
		push	ecx								;push for typeFunction (Procedure_xxxx)
		mov	edi, [(NMDE_S ptr ebx).entryLenght]
		mov	currentOffset, ecx					;we'll use this variable in Procedure_xxxx

		push	edi
		push	ecx		;pEntry
		push	dword ptr [offset @Table1+edx*4]
		call	StringComplete, offset DebugRecordType, eax
		add	esp, 03h*04h
		add	ebx, SIZE NMDE_S

		call	[offset Table2+edx*4]
		jmp	@Type2_Next
Table2:
	DWORD offset Procedure_Unknown
	DWORD offset Procedure_GTYP
	DWORD offset Procedure_STTB
	DWORD offset Procedure_NMTP
	DWORD offset Procedure_TYTB
	DWORD offset Procedure_HSHT
	DWORD offset Procedure_SYMD
	DWORD offset Procedure_SRCP
	DWORD offset Procedure_FPOD
;EndTable
@Type2_Unknown:
		xor	edx, edx
		jmp	@Type2_Proceed
@Type2_End:

	
;--------------------------------------------------------------------------------------------------------------------------
;Make CurrentDir\textName.txt
;
		mov	ebx, offset currentDir
		xor	ecx, ecx
		mov	esi, ebx				;source
		mov	edi, offset tempBuffer
;get the length of currentDir path
@Loop9:
		cmp	byte ptr [ebx], NULL	;are we at the end
		je	@CurrentAtTheEnd2
		inc	ecx
		inc	ebx
		jmp	@Loop9
;strCpy(tempBuffer, currentDir);
@CurrentAtTheEnd2:
		cld
		repnz movsb

		mov	ebx, [text.pFileName]	;source
;strCat(tempBuffer, "\\");
		mov	byte ptr [edi], '\'
		inc	edi

		xor	ecx, ecx
		mov	esi, ebx				;source
;get the length of the textName
@Loop10:
		cmp	byte ptr [ebx], NULL	;are we at the end
		je	@TextNameAtTheEnd
		inc	ecx
		inc	ebx
		jmp	@Loop10
;strCat(tempBuffer, textName);
@TextNameAtTheEnd:
		inc	ecx					;zero byte too
		cld
		repnz movsb

;--------------------------------------------------------------------------------------------------------------------------
;Write text file
;

		call	CreateFile, offset tempBuffer, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_ARCHIVE, NULL
		cmp	eax, INVALID_HANDLE_VALUE
		je	@ERROR_FileError
		mov	[text.hFile], eax

		xor	ecx, ecx
		xor	eax, eax
		dec	ecx			;counter set
		mov	edi, [text.hMapped]
		cld
		repnz scasb
		not	ecx				;not (one number less than neg)
		dec	ecx

		call	WriteFile, text.hFile, text.hMapped, ecx, offset BytesReadWrite, NULL
		test	eax, eax
		setz	bl			;set bl to 1 if eax=NULL

		call	CloseHandle, text.hFile
		test	eax, eax
		je	@ERROR_FileError

		test	bl, bl		;do we have 1
		jnz	@ERROR_FileReadingError
		jmp	@FreeMemory
;--------------------------------------------------------------------------------------------------------------------------
;Error handling
;
.data
errorCaption		db"Error!",0
.code
@ERROR_CommandLine:
		mov	eax, ERROR_COMMANDLINE
		jmp	@ErrorHandling
@ERROR_FileError:
		mov	eax, ERROR_FILE
		jmp	@ErrorHandling
@ERROR_AllocatingError:
		mov	eax, ERROR_ALLOCATE
		jmp	@ErrorHandling
@ERROR_FileReadingError:
		mov	eax, ERROR_READING
@ErrorHandling:
		mov	ebx, offset errorBuffer
		call	LoadString, hInstance, eax, ebx, 64
		call	MessageBox, NULL, ebx, offset errorCaption, MB_OK

@FreeMemory:
		mov	eax, [nms.hMapped]
		test	eax, eax
		jz	@NoMemoryAllocated
		call	GlobalFree, eax

		mov	eax, [text.hMemUnlocked]
		test	eax, eax
		jz	@NoMemoryAllocated
		call	GlobalFree, ebx
@NoMemoryAllocated:
@ExitProcess:
		call	ExitProcess, NULL

;--------------------------------------------------------------------------------------------------------------------------
;--------------------------------------------------------------------------------------------------------------------------
;--------------------------------------------------------------------------------------------------------------------------
;Type procedures
;
;EAX=pointer to 1st free byte in textBuffer
;EBX=current NMDE structure
;ESI=pNMSFileMapped [nms.hMapped]
;EDX=entryIndex
;
Procedure_Unknown PROC pEntry_:POINTER	;don't bother this procedure is just to be on the safe side
		ret
ENDP

Procedure_GTYP PROC pEntry_:POINTER
.data
sP_GTYP		db 13,10,"GTYP Header:",13,10,13,10
			db"offset  data     name",13,10
			db"0       ULONG    GTYP(string)",13,10
			db"4       ULONG    sectionLenght",13,10
			db"8       ULONG    %x (offNMTP)",13,10
			db"C       ULONG    %x (offSTTB)",13,10
			db"10      ULONG    %x (offTYTB)",13,10
			db"14      ULONG    %x (offHSHT)",13,10
			db"18      ULONG    %x",13,10
			db"1C      ULONG    %x",13,10,0
.code
		mov	edi, pEntry_
		add	edi, esi

		push	dword ptr [(GTYP_HEADER ptr edi).N2_GTYP]
		push	dword ptr [(GTYP_HEADER ptr edi).N1_GTYP]
		push	dword ptr [(GTYP_HEADER ptr edi).offHSHT]
		push	dword ptr [(GTYP_HEADER ptr edi).offTYTB]
		push	dword ptr [(GTYP_HEADER ptr edi).offSTTB]
		push	dword ptr [(GTYP_HEADER ptr edi).offNMTP]
		call	StringComplete, offset sP_GTYP, eax
		add	esp, 06h*04h
		ret
ENDP

Procedure_STTB PROC pEntry_:POINTER
USES ebx, edx, esi
.data
sP_STTB		db 13,10," [%x] %s",0
nextLine		db 13,10,0
.code
;eax=pointer to 1st free byte in textBuffer
		xor	edx, edx				;counter
		mov	ebx, [nms.pNameOffsets]	;offset in pString
		mov	esi, [nms.pStrings]		;pStrings
		mov	edi, [nms.cNames]	;number of names in STTB

;eax=pointer to 1st free byte in textBuffer
;ebx=pointer to offsets (nms.pNameOffsets)
;edx=counter
;esi=pointer to strings (nms.pStrings)
;edi=number of names in STTB
@P_STTB_Loop1:	
		mov	ecx, [ebx+edx*4]	;get the offset
		add	ecx, esi			;ecx points to wanted string
		push	ecx
		push	edx
		inc	edx
		call	StringComplete, offset sP_STTB, eax
		add	esp, 02h*04h
		cmp	edx, edi
		jb	@P_STTB_Loop1

		call	StringComplete, offset nextLine, eax
		ret
ENDP

Procedure_NMTP PROC pEntry_:POINTER
USES ebx, edx, esi
.data
sP_NMTP_H		db 13,10,"NMTP Header:",13,10
			db"offset    data      name",13,10
			db"0         ULONG     NMTP(string)",13,10
			db"4         ULONG     sectionLenght",13,10
			db"8         ULONG     %x (cTypes)",13,10
			db"C         ULONG     %x",13,10
			db"10        ULONG     %x",13,10,13,10,0
.code
local	pFirstTypeData:DWORD
local	pCurrentTypeOffset:DWORD
local	firstTypeDataOffset:DWORD

;eax=pointer to 1st free byte in textBuffer
;edx=counter
;ESI=pNMSFileMapped [nms.hMapped]
		mov	ebx, pEntry_
		add	ebx, esi
;NMTP Header
		mov	edx, dword ptr [(NMTP_HEADER ptr ebx).cTypes]
		push	dword ptr [(NMTP_HEADER ptr ebx).N2_NMTP_HEADER]
		push	dword ptr [(NMTP_HEADER ptr ebx).N1_NMTP_HEADER]
		push	edx
		add	ebx, SIZE NMTP_HEADER
		call	StringComplete, offset sP_NMTP_H, eax
		add	esp, 03h*04h

		mov	ecx, [currentOffset]
		add	ecx, SIZE NMTP_HEADER

		lea	edi, [edx*4]					;size of all offsets
		mov	[pCurrentTypeOffset], ebx
		add	ecx, edi
		mov	[currentOffset], ecx
		add	edi, ebx						;edi->1st typeData
		mov	[pFirstTypeData], edi
		inc	edx							;prepare for loop
		mov	[firstTypeDataOffset], ecx

;eax=pointer to 1st free byte in textBuffer
;edx=counter(in reverse)
;esi=index counter
;edi=current typeData
		mov	esi, 01000h-01h				;first type
@P_NMTP_NextTypeLoop:
		dec	edx
		jz	@P_NMTP_EndNextTypeLoop

		inc	esi							;update index counter
		mov	edi, [pCurrentTypeOffset]
		mov	ecx, [firstTypeDataOffset]
		add	[pCurrentTypeOffset], 4			;update the pointer

		mov	edi, [edi]					;get the offset
		add	ecx, edi
		mov	[currentOffset], ecx
		add	edi, [pFirstTypeData]			;edi points to currentTypeData

;get lf_index
		mov	ecx, [edi]
		cmp	ecx, TYPE_LF_ARRAY
		je	@P_NMTP_ARRAY

		cmp	ecx, TYPE_LF_STRUCT
		je	@P_NMTP_STRUCT
;not yet
;		cmp	ecx, TYPE_LF_STRUCT			
;		je	@P_NMTP_STRUCT

		cmp	ecx, TYPE_LF_PROCEDURE
		je	@P_NMTP_PROCEDURE

		cmp	ecx, TYPE_LF_LABEL
		je	@P_NMTP_LABEL

		cmp	ecx, TYPE_LF_ARGLIST
		je	@P_NMTP_ARGLIST

		cmp	ecx, TYPE_LF_DERIVED
		je	@P_NMTP_DERIVED

		cmp	ecx, TYPE_LF_MEMBER
		je	@P_NMTP_MEMBER

;UNKNOWN type
.data
sP_NMTP_UnknownS	db"   Unknown type (%x)  [file offset: %x]",13,10
				db"       offset       data      name",13,10
				db"       0            ULONG     %x (lf_index)",13,10
				db"        ...",13,10,0
;sP_NMTP_Unknown	db"       %x",13,10,0
.code
		push	dword ptr [edi]				;typeNumber
		push	[currentOffset]
		push	esi
		call	StringComplete, offset sP_NMTP_UnknownS, eax
		add	esp, 03h*04h
		jmp	@P_NMTP_NextTypeLoop

@P_NMTP_ARRAY:
.data
sP_NMTP_ARRAY		db"   Array type (%x)  [file offset: %x]",13,10
				db"       offset       data      name",13,10
				db"       0            ULONG     %x (lf_index)",13,10
				db"       4            ULONG     %x (elemType)",13,10
				db"       8            ULONG     %x",13,10
				db"       C            SHORT     %2x",13,10
				db"       E            ULONG     %x (lenght)",13,10
				db"       12           ULONG     %x (indexType)",13,10
				db"       16           ULONG     %x",13,10
				db"       1A           ULONG     %x (lenght)",13,10
				db"       1E           SHORT     %2x",13,10,0
.code
		movzx ecx, word ptr [(DATAS_LF_ARRAY ptr edi).N4_LF_ARRAY]
		push	ecx
		push	dword ptr [(DATAS_LF_ARRAY ptr edi).length2]
		push	dword ptr [(DATAS_LF_ARRAY ptr edi).N3_LF_ARRAY]
		push	dword ptr [(DATAS_LF_ARRAY ptr edi).indexType]
		push	dword ptr [(DATAS_LF_ARRAY ptr edi).length]
		movzx ecx, word ptr [(DATAS_LF_ARRAY ptr edi).N2_LF_ARRAY]
		push	ecx
		push	dword ptr [(DATAS_LF_ARRAY ptr edi).N1_LF_ARRAY]
		push	dword ptr [(DATAS_LF_ARRAY ptr edi).elemType]
		push	dword ptr [(DATAS_LF_ARRAY ptr edi).lf_index]
		push	[currentOffset]
		push	esi
		call	StringComplete, offset sP_NMTP_ARRAY, eax
		add	esp, 0Bh*4
		jmp	@P_NMTP_NextTypeLoop

@P_NMTP_STRUCT:
.data
sP_NMTP_STRUCT		db"   Struct type (%x)  [file offset: %x]",13,10
				db"       offset    data      name",13,10
				db"       0            ULONG     %x (lf_index)",13,10
				db"       4            ULONG     %x (derivedType)",13,10
				db"       8            ULONG     %x (iName) [%s]",13,10
				db"       C            SHORT     %2x (property)",13,10
				db"       E            ULONG     %x (cFields)",13,10
				db"       12           ULONG     %x (lenght)",13,10
				db"       16           ULONG     %x",13,10
				db"       1A           ULONG     %x",13,10
				db"       1E           SHORT     %2x",13,10,0
.code
		movzx ecx, word ptr [(DATAS_LF_STRUCT ptr edi).N3_LF_STRUCT]
		push	ecx
		push	dword ptr [(DATAS_LF_STRUCT ptr edi).N2_LF_STRUCT]
		push	dword ptr [(DATAS_LF_STRUCT ptr edi).N1_LF_STRUCT]
		push	dword ptr [(DATAS_LF_STRUCT ptr edi).length_LF_STRUCT]
		push	dword ptr [(DATAS_LF_STRUCT ptr edi).cFields]
		movzx ebx, word ptr [(DATAS_LF_STRUCT ptr edi).property]
		push	ebx
		mov	ecx, [(DATAS_LF_STRUCT ptr edi).iName]
			mov	ebx, [nms.pNameOffsets]		;get pointer to strings offsets
			mov	ebx, [ebx+ecx*4]			;get the offset
			add	ebx, [nms.pStrings]
			push	ebx
		push	ecx
		push	dword ptr [(DATAS_LF_STRUCT ptr edi).derivedType]
		push	dword ptr [(DATAS_LF_STRUCT ptr edi).lf_index]
		push	[currentOffset]
		push	esi
		call	StringComplete, offset sP_NMTP_STRUCT, eax
		add	esp, 0Ch*04h
		jmp	@P_NMTP_NextTypeLoop

@P_NMTP_PROCEDURE:
.data
sP_NMTP_PROCEDURE	db"   Procedure type (%x)  [file offset: %x]",13,10
				db"       offset       data      name",13,10
				db"       0            ULONG     %x (lf_index)",13,10
				db"       4            ULONG     %x (argList)",13,10
				db"       8            ULONG     %x (rType)",13,10
				db"       C            ULONG     %x (call)",13,10
				db"       10           ULONG     %x (argCount)",13,10,0
.code
		push	dword ptr [(DATAS_LF_PROCEDURE ptr edi).argCount]
		push	dword ptr [(DATAS_LF_PROCEDURE ptr edi).call_LF_PROCEDURE]
		push	dword ptr [(DATAS_LF_PROCEDURE ptr edi).rType]
		push	dword ptr [(DATAS_LF_PROCEDURE ptr edi).argList]
		push	dword ptr [(DATAS_LF_PROCEDURE ptr edi).lf_index]
		push	[currentOffset]
		push	esi
		call	StringComplete, offset sP_NMTP_PROCEDURE, eax
		add	esp, 07h*04h
		jmp	@P_NMTP_NextTypeLoop

@P_NMTP_LABEL:
.data
sP_NMTP_LABEL		db"   Label type (%x)  [file offset: %x]",13,10
				db"       offset       data      name",13,10
				db"       0            ULONG     %x (lf_index)",13,10
				db"       4            ULONG     %x (mode)",13,10,0
.code
		push	dword ptr [(DATAS_LF_LABEL ptr edi).mode]
		push	dword ptr [(DATAS_LF_LABEL ptr edi).lf_index]
		push	[currentOffset]
		push	esi
		call	StringComplete, offset sP_NMTP_LABEL, eax
		add	esp, 04h*04h
		jmp	@P_NMTP_NextTypeLoop

@P_NMTP_ARGLIST:
.data
sP_NMTP_ARGLIST		db"   Arglist type (%x)  [file offset: %x]",13,10
					db"       offset       data      name",13,10
					db"       0            ULONG     %x (lf_index)",13,10
					db"       4            ULONG     %x",13,10
					db"       8            ULONG     %x (argCount)",13,10
					db"       C   argCount*ULONG     %x (varType)",13,10,0
sP_NMTP_ARGTYPE		db"       *            ULONG     %x (varType)",13,10,0
sP_NMTP_ARGTYPEERROR	db"ERROR: argCount = 0",13,10,0
.code
;ecx, ebx
		mov	ebx, [(DATAS_LF_ARGLIST ptr edi).argCount_LF_ARGLIST]
		test	ebx, ebx
		jnz	@P_NMTP_ARGTYPE_HasArguments
		push	dword ptr NULL
		jmp	@P_NMTP_ARGTYPE_Proceed
@P_NMTP_ARGTYPE_HasArguments:
		push	dword ptr [(DATAS_LF_ARGLIST ptr edi).varType]
@P_NMTP_ARGTYPE_Proceed:
		mov	ebx, [(DATAS_LF_ARGLIST ptr edi).argCount_LF_ARGLIST]
		push	ebx
		push	dword ptr [(DATAS_LF_ARGLIST ptr edi).N1_LF_ARGLIST]
		push	dword ptr [(DATAS_LF_ARGLIST ptr edi).lf_index]
		push	[currentOffset]
		push	esi
		call	StringComplete, offset sP_NMTP_ARGLIST, eax
		add	esp, 06h*04h
		test	ebx, ebx
		jz	@P_NMTP_ARGTYPE_ERROR

		add	edi, SIZE DATAS_LF_ARGLIST
@P_NMTP_ARGTYPE_Loop:
		dec	ebx			;first is in sP_NMTP_ARGLIST
		test	ebx, ebx
		jz	@P_NMTP_NextTypeLoop
		push	dword ptr [edi]
		call	StringComplete, offset sP_NMTP_ARGTYPE, eax
		add	edi, 4
		add	esp, 01h*04h
		jmp	@P_NMTP_ARGTYPE_Loop
@P_NMTP_ARGTYPE_ERROR:
		call	StringComplete, offset sP_NMTP_ARGTYPEERROR, eax
		jmp	@P_NMTP_NextTypeLoop

@P_NMTP_DERIVED:
.data
sP_NMTP_DERIVED:		db"   Derived type (%x) [file offset: %x]",13,10
					db"       offset       data      name",13,10
					db"       0            ULONG     %x (lf_index)",13,10
					db"       4            ULONG     %x (NULL)",13,10
					db"       8            ULONG     %x (cType)",13,10
					db"       C      cType*ULONG     %x (memType)",13,10,0
sP_NMTP_DERTYPE		db"       *            ULONG     %x (memType)",13,10,0
sP_NMTP_DERTYPEERROR	db"ERROR: memCount = 0",13,10,0
.code
		mov	ebx, [(DATAS_LF_DERIVED ptr edi).memCount]
		test	ebx, ebx
		jnz	@P_NMTP_DERIVED_HasMembers
		push	dword ptr NULL
		jmp	@P_NMTP_DERIVED_Proceed
@P_NMTP_DERIVED_HasMembers:		
		push	dword ptr [(DATAS_LF_DERIVED ptr edi).memType]
@P_NMTP_DERIVED_Proceed:
		push	ebx
		push	dword ptr [(DATAS_LF_DERIVED ptr edi).N1_LF_DERIVED]
		push	dword ptr [(DATAS_LF_DERIVED ptr edi).lf_index]
		push	[currentOffset]
		push	esi
		call	StringComplete, offset sP_NMTP_DERIVED, eax
		add	esp, 06h*04h
		test	ebx, ebx
		jz	@P_NMTP_DERIVED_ERROR

		add	edi, SIZE DATAS_LF_DERIVED
@P_NMTP_DERIVEDLoop:
		dec	ebx			;first is in sP_NMTP_ARGLIST
		test	ebx, ebx
		jz	@P_NMTP_NextTypeLoop
		push	dword ptr [edi]
		call	StringComplete, offset sP_NMTP_DERTYPE, eax
		add	edi, 4
		add	esp, 01h*04h
		jmp	@P_NMTP_DERIVEDLoop
@P_NMTP_DERIVED_ERROR:
		call	StringComplete, offset sP_NMTP_DERTYPEERROR, eax
		jmp	@P_NMTP_NextTypeLoop
	
@P_NMTP_MEMBER:
.data
sP_NMTP_MEMBER		db"   Member type (%x)  [file offset: %x]",13,10
				db"       offset       data      name",13,10
				db"       0            ULONG     %x (lf_index)",13,10
				db"       4            ULONG     %x (indexType)",13,10
				db"       8            ULONG     %x (iName) [%s]",13,10
				db"       C            SHORT     %2x (access)",13,10
				db"       E            SHORT     %2x (offset)",13,10
				db"       10           ULONG     %x (? browserOffset)",13,10,0
.code
		push	dword ptr [(DATAS_LF_MEMBER ptr edi).N1_LF_MEMBER]
		movzx ecx, word ptr [(DATAS_LF_MEMBER ptr edi).offset]
		push	ecx
		movzx ebx, word ptr [(DATAS_LF_MEMBER ptr edi).access]
		push	ebx
		mov	ecx, [(DATAS_LF_MEMBER ptr edi).iName]
			mov	ebx, [nms.pNameOffsets]	;get the offset
			mov	ebx, [ebx+ecx*4]
			add	ebx, [nms.pStrings]
			push	ebx
		push	ecx
		push	dword ptr [(DATAS_LF_MEMBER ptr edi).indexType_LF_MEMBER]
		push	dword ptr [(DATAS_LF_MEMBER ptr edi).lf_index]
		push	[currentOffset]
		push	esi
		call	StringComplete, offset sP_NMTP_MEMBER, eax
		add	esp, 09h*04h
		jmp	@P_NMTP_NextTypeLoop

@P_NMTP_EndNextTypeLoop:
		ret

ENDP
Procedure_TYTB PROC pEntry_:POINTER
USES ebx, edx, esi
.data
sP_TYTB_H		db 13,10,"TYTB Header:",13,10
			db"offset    data      name",13,10
			db"0         ULONG     TYTB(string)",13,10
			db"4         ULONG     sectionLenght",13,10
			db"8         ULONG     %x (cTypes)",13,10
			db"C         ULONG     %x (offTypeTables)",13,10
			db"10        ULONG     %x",13,10
			db"14        ULONG     %x",13,10,13,10
			db"TypeTable: [file offset: %x]",13,10,0
sP_TYTB_TT	db"   offset    data      name",13,10
			db"   0         ULONG     %x (type)",13,10
			db"   4         ULONG     %x (iNameType) [%s]",13,10,0
.code
;eax=pointer to 1st free byte in textBuffer
		mov	ebx, pEntry_
		add	ebx, esi

		mov	edx, [(TYTB_HEADER ptr ebx).cTypes]
		push	dword ptr [(TYTB_HEADER ptr ebx).offTypeTables]
		push	dword ptr [(TYTB_HEADER ptr ebx).N2_TYTB]
		push	dword ptr [(TYTB_HEADER ptr ebx).N1_TYTB]
		mov	ebx, [(TYTB_HEADER ptr ebx).offTypeTables]
		push	ebx
		push	edx
		call	StringComplete, offset sP_TYTB_H, eax
		add	esp, 05h*04h
		add	ebx, esi					;points to TypeTables
;test if we have any types (just to be on the safe side)
;(if everything is ok they should be, because if they are not, TYTB section shouldn't be in NMS file)
		test	edx, edx
		jz	@P_TYTB_noTypes

;eax=pointer to 1st free byte in textBuffer
;ebx=pointer to current TypeTable
;edx=counter
;esi=pNameOffsets
		mov	esi, [nms.pNameOffsets]		;get pointer to offsets
@P_TYTB_TTLoop:
		mov	ecx, [(TYPETABLE ptr ebx).iNameType]
;get the pointer to the string
			mov	edi, [esi+ecx*4]			;get offset to string
			add	edi, [nms.pStrings]
			push	edi						;pointer to string from the index
		push	ecx						;iNameType
		push	dword ptr [(TYPETABLE ptr ebx).type]
		dec	edx						;decrease counter
		add	ebx, SIZE TYPETABLE			;to next table
		call	StringComplete, offset sP_TYTB_TT, eax
		add	esp, 03h*04h
		test	edx, edx
		jnz	@P_TYTB_TTLoop
@P_TYTB_noTypes:
		ret
ENDP

Procedure_HSHT PROC pEntry_:POINTER
USES ebx, edx, esi
.data
sP_HSHT_H		db 13,10,"HSHT Header:",13,10
			db"offset    data      name",13,10
			db"0         ULONG     HSHT(string)",13,10
			db"4         ULONG     sectionLenght",13,10
			db"8         ULONG     %x (sizeTableOffsets)",13,10
			db"C         ULONG     %x (cTypes)",13,10
			db"10        ULONG     %x (offTableOffsets)",13,10
			db"14        ULONG     %x (offTypeTables)",13,10
			db"18        ULONG     %x",13,10
			db"1C        ULONG     %x",13,10,0
.code
LOCAL	typeOffset:DWORD
;eax=pointer to 1st free byte in textBuffer
		mov	ecx, pEntry_
		add	ecx, esi

		mov	edi, [(HSHT_HEADER ptr ecx).offTypeTables_HSHT]
		mov	ebx, [(HSHT_HEADER ptr ecx).offTableOffsets]
		mov	edx, [(HSHT_HEADER ptr ecx).cTypes_HSHT]
		mov	[currentOffset], edi
		push	dword ptr [(HSHT_HEADER ptr ecx).N2_HSHT]
		push	dword ptr [(HSHT_HEADER ptr ecx).N1_HSHT]
		push	edi
		push	ebx
		push	edx
		push	dword ptr [(HSHT_HEADER ptr ecx).sizeTableOffsets]
		add	edi, esi
		call	StringComplete, offset sP_HSHT_H, eax
		add	esp, 06h*04h
		add	ebx, esi

.data
sP_HSHT_SUBS1		db 13,10,"HSHTTypeTablesOffsets section:",13,10
				db"offset    data      name",13,10
				db"0         ULONG     %x",13,10
				db"4         ULONG     %x",13,10
				db"8         ULONG     %x",13,10
				db"C         ULONG     %x",13,10
				db"10        ULONG     %x",13,10
				db"14        ULONG     %x",13,10
				db"18        ULONG     %x",13,10
				db"1C        ULONG     %x",13,10
				db"20        ULONG     %x",13,10
				db"24        ULONG     %x",13,10
				db"28        ULONG     %x",13,10
				db"2C        ULONG     %x",13,10
				db"30        ULONG     %x",13,10
				db"34        ULONG     %x",13,10
				db"38        ULONG     %x",13,10
				db"3C        ULONG     %x",13,10
				db"40        ULONG     %x",13,10
				db"44        ULONG     %x",13,10
				db"48        ULONG     %x",13,10
				db"4C        ULONG     %x",13,10
				db"50        ULONG     %x",13,10
				db"54        ULONG     %x",13,10
				db"58        ULONG     %x",13,10
				db"5C        ULONG     %x",13,10
				db"60        ULONG     %x",13,10
				db"64        ULONG     %x",13,10
				db"68        ULONG     %x",13,10
				db"6C        ULONG     %x",13,10
				db"70        ULONG     %x",13,10
				db"74        ULONG     %x",13,10
				db"78        ULONG     %x",13,10
				db"7C        ULONG     %x",13,10
				db"80        ULONG     %x",13,10
				db"84        ULONG     %x",13,10
				db"88        ULONG     %x",13,10
				db"8C        ULONG     %x",13,10
				db"90        ULONG     %x",13,10,13,10
				db"HSHT Type Tables:",13,10,0
.code
;eax=pointer to 1st free byte i ntextBuffer
;ebx=pointer to TableOffsets
;edx=cTypes
;(esi)=pNMSFileMapped [nms.hMapped]
;edi=pointer to TypeTables
		push	dword ptr [ebx+090h]
		push	dword ptr [ebx+08Ch]
		push	dword ptr [ebx+088h]
		push	dword ptr [ebx+084h]
		push	dword ptr [ebx+080h]
		push	dword ptr [ebx+07Ch]
		push	dword ptr [ebx+078h]
		push	dword ptr [ebx+074h]
		push	dword ptr [ebx+070h]
		push	dword ptr [ebx+06Ch]
		push	dword ptr [ebx+068h]
		push	dword ptr [ebx+064h]
		push	dword ptr [ebx+060h]
		push	dword ptr [ebx+05Ch]
		push	dword ptr [ebx+058h]
		push	dword ptr [ebx+054h]
		push	dword ptr [ebx+050h]
		push	dword ptr [ebx+04Ch]
		push	dword ptr [ebx+048h]
		push	dword ptr [ebx+044h]
		push	dword ptr [ebx+040h]
		push	dword ptr [ebx+03Ch]
		push	dword ptr [ebx+038h]
		push	dword ptr [ebx+034h]
		push	dword ptr [ebx+030h]
		push	dword ptr [ebx+02Ch]
		push	dword ptr [ebx+028h]
		push	dword ptr [ebx+024h]
		push	dword ptr [ebx+020h]
		push	dword ptr [ebx+01Ch]
		push	dword ptr [ebx+018h]
		push	dword ptr [ebx+014h]
		push	dword ptr [ebx+010h]
		push	dword ptr [ebx+0Ch]
		push	dword ptr [ebx+08h]
		push	dword ptr [ebx+04h]
		push	dword ptr [ebx]
		call	StringComplete, offset sP_HSHT_SUBS1, eax
		add	esp, 025h*04h

.data
sP_HSHT_TT	db"   Type table [file offset: %x] :",13,10
			db"   offset    data      name",13,10
			db"   0         ULONG     %x (offPreviousTable)",13,10
			db"   4         ULONG     %x (hashNumber)",13,10
			db"   8         ULONG     %x (iNameType) [%s]",13,10
			db"   C         ULONG     %x (type)",13,10
			db"   10        ULONG     %x",13,10,0
.code
;eax=pointer to 1st free byte in textBuffer
;edx=cTypes
;esi=pNameOffsets
;edi=pointer to current TypeTable
;
;test if we have any tables
;(if everything is ok they should be, because if they are not, HSHT section shouldn't be in NMS file)
		test	edx, edx
		je	@P_HSHT_noTypes
		mov	esi, [nms.pNameOffsets]		;get pointer to offsets
@P_HSHT_TTLoop:
		push	dword ptr [(HSHT_TYPETABLE ptr edi).N1_TYPETABLE]
		push	dword ptr [(HSHT_TYPETABLE ptr edi).type_HSHT]
		mov	ecx, [(HSHT_TYPETABLE ptr edi).iNameType_HSHT]
;get the pointer to the string
			mov	ebx, [esi+ecx*4]
			add	ebx, [nms.pStrings]
			push	ebx
		push	ecx
		push	dword ptr [(HSHT_TYPETABLE ptr edi).hashNumber]
		push	dword ptr [(HSHT_TYPETABLE ptr edi).offPreviousTable]
		push	[currentOffset]
		add	[currentOffset], SIZE HSHT_TYPETABLE
		call	StringComplete, offset sP_HSHT_TT, eax
		add	edi, SIZE HSHT_TYPETABLE
		add	esp, 07h*04h
		dec	edx
		test	edx, edx
		jnz	@P_HSHT_TTLoop
@P_HSHT_noTypes:
		ret
ENDP



Procedure_SYMD PROC pEntry_:POINTER
USES ebx, edx, esi
.data
sP_SYMD_H		db 13,10,"SYMD Header:",13,10
			db"offset    data     name",13,10
			db"0         ULONG    SYMD(string)",13,10
			db"4         ULONG    sectionLenght",13,10
			db"8         ULONG    %x (pSegmentData_header)",13,10
			db"C         ULONG    %x",13,10
			db"10        ULONG    %x",13,10
			db"14        ULONG    %x",13,10
			db"18        ULONG    %x",13,10
			db"1C        ULONG    %x",13,10
			db"20        ULONG    %x",13,10
			db"24        ULONG    %x",13,10
			db"28        ULONG    %x",13,10,0
.code
local	pSegmentDataHeader:POINTER
local	cSegmentsCurrent:DWORD
local	cProcedures_:DWORD

;eax=pointer to 1st free byte in textBuffer
;ESI=pNMSFileMapped [nms.hMapped]
		mov	ebx, pEntry_
		add	ebx, esi
;SYMD Header
		push	dword ptr [(SYMD_HEADER ptr ebx).N8_SYMD_HEADER]
		push	dword ptr [(SYMD_HEADER ptr ebx).N7_SYMD_HEADER]
		push	dword ptr [(SYMD_HEADER ptr ebx).N6_SYMD_HEADER]
		push	dword ptr [(SYMD_HEADER ptr ebx).N5_SYMD_HEADER]
		push	dword ptr [(SYMD_HEADER ptr ebx).N4_SYMD_HEADER]
		push	dword ptr [(SYMD_HEADER ptr ebx).N3_SYMD_HEADER]
		push	dword ptr [(SYMD_HEADER ptr ebx).N2_SYMD_HEADER]
		push	dword ptr [(SYMD_HEADER ptr ebx).N1_SYMD_HEADER]
		mov	ebx, [(SYMD_HEADER ptr ebx).offSegmentData_header]
		push	ebx
		call	StringComplete, offset sP_SYMD_H, eax
		add	esp, 09h*04h
		mov	[currentOffset], ebx
		add	ebx, esi
;SegmentData
.data
sP_SYMD_SEGH	db 13,10,"Segments header (offset %x):",13,10
			db"offset    data     name",13,10
			db"0         ULONG    %x (subSectionLenght)",13,10
			db"4         ULONG    %x (cSourceFiles)",13,10
			db"8         ULONG    %x (cSegments)",13,10,0
.code
;SegmentData_header(subSection):
		mov	[cSegmentsCurrent], 0
		mov	[pSegmentDataHeader], ebx

		push	dword ptr [(SEGMENTDATA_HEADER ptr ebx).cSegments]
		push	dword ptr [(SEGMENTDATA_HEADER ptr ebx).cSourceFiles]
		push	dword ptr [(SEGMENTDATA_HEADER ptr ebx).subSectionLength]
		push	[currentOffset]
		call	StringComplete, offset sP_SYMD_SEGH, eax
		add	esp, 04h*04h
;Segments
.data
sP_SYMD_SDTABLE	db 13,10,"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~",13,10
				db"SegmentData Table (offset %x):",13,10
				db"offset    data     name",13,10
				db"0         SHORT    %2x (nSeg)",13,10
				db"2         ULONG    %x (iNameSegment) [%s]",13,10		;moras popravit če je FFFFFFFF => no string
				db"6         ULONG    %x",13,10
				db"A         ULONG    %x (physSize)",13,10
				db"E         ULONG    %x (offProcDef)",13,10
				db"12        ULONG    %x (cProcedures)",13,10
				db"16        ULONG    %x (offLVarDef)",13,10
				db"1A        ULONG    %x (offSCLineDef)",13,10
				db"1E        ULONG    %x (offVLPDef)",13,10
				db"22        ULONG    %x (cVLP)",13,10
				db"26        ULONG    %x (offVLPOffsets)",13,10
				db"2A        ULONG    %x (offSourceSDef)",13,10
				db"2E        ULONG    %x (cSourceSec)",13,10
				db"32        ULONG    %x (offSCLineDef2)",13,10,0
.code
;eax=pointer to 1st free byte in textBuffer
;ebx=points to current SEGMENTDATA structure
;esi=pNMSFileMapped [nms.hMapped]
		add	ebx, (SIZE SEGMENTDATA_HEADER)-(SIZE SEGMENTDATA)	; -(..) (minus because of the loop)
@P_SYMD_SegLoop:
		add	ebx, SIZE SEGMENTDATA
		push	dword ptr [(SEGMENTDATA ptr ebx).offSCLineDef2]
		push	dword ptr [(SEGMENTDATA ptr ebx).cSourceSec]
		push	dword ptr [(SEGMENTDATA ptr ebx).offSourceSDef]
		push	dword ptr [(SEGMENTDATA ptr ebx).offVLPOffsets]
		push	dword ptr [(SEGMENTDATA ptr ebx).cVLP]
		push	dword ptr [(SEGMENTDATA ptr ebx).offVLPDef]
		push	dword ptr [(SEGMENTDATA ptr ebx).offSCLineDef]
		push	dword ptr [(SEGMENTDATA ptr ebx).offLVarDef]
		push	dword ptr [(SEGMENTDATA ptr ebx).cProcedures]
		push	dword ptr [(SEGMENTDATA ptr ebx).offProcDef]
		push	dword ptr [(SEGMENTDATA ptr ebx).physSize]
		push	dword ptr [(SEGMENTDATA ptr ebx).N1_SEGMENTDATA]
		mov	ecx, [(SEGMENTDATA ptr ebx).iNameSegment]
			mov	edx, [nms.pNameOffsets]
			mov	edx, [edx+ecx*4]			;get the offset
			add	edx, [nms.pStrings]
			push	edx
		push	ecx
		movzx edx, word ptr [(SEGMENTDATA ptr ebx).nSeg]
		push	edx
;offset in file
		mov	ecx, ebx
		sub	ecx, esi
		push	ecx
		call	StringComplete, offset sP_SYMD_SDTABLE, eax
		add	esp, 010h*04h

;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		mov	ecx, [(SEGMENTDATA ptr ebx).cProcedures]
		test	ecx, ecx
		je	@P_SYMD_NoProceduresInSegment
		mov	[cProcedures_], ecx
.data
sP_SYMD_ProcDefS	db 13,10,"Procedure defenitions:",13,10,0
sP_SYMD_ProcDef	db"  [file offset: %x]",13,10
				db"     offset    data      name",13,10
				db"     0         ULONG     %x (offStartProc)",13,10
				db"     4         ULONG     %x (offEndProc)",13,10
				db"     8         ULONG     %x (offLocalVariables)",13,10
				db"     C         ULONG     %x (cLocalVariables)",13,10
				db"     10        ULONG     %x",13,10
				db"     14        ULONG     %x",13,10
				db"     18        ULONG     %x",13,10,0
.code
;eax=pointer to 1st free byte in textBuffer
;ebx=points to current SEGMENTDATA structure
;edx=number of local variables
;esi=pNMSFileMapped [nms.hMapped]
;edi=pointer to current symbolTable structure
		call	StringComplete, offset sP_SYMD_ProcDefS, eax
		mov	edi, ebx
		add	edi, [(SEGMENTDATA ptr ebx).offProcDef]
		xor	edx, edx								;number of local variables
@P_SYMD_ProcDefLoop:
		push	dword ptr[(SEGDATA_PROCEDURE ptr edi).M1]
		push	dword ptr[(SEGDATA_PROCEDURE ptr edi).N2_SD_PROCEDURE]
		push	dword ptr[(SEGDATA_PROCEDURE ptr edi).N1_SD_PROCEDURE]
		add	edx, dword ptr[(SEGDATA_PROCEDURE ptr edi).cLocalVariables]
		push	dword ptr[(SEGDATA_PROCEDURE ptr edi).cLocalVariables]
		push	dword ptr[(SEGDATA_PROCEDURE ptr edi).offLocalVariables]
		push	dword ptr[(SEGDATA_PROCEDURE ptr edi).offEndProc]
		push	dword ptr[(SEGDATA_PROCEDURE ptr edi).offStartProc]
;offset in file
		mov	ecx, edi
		sub	ecx, esi
		push	ecx
		call	StringComplete, offset sP_SYMD_ProcDef, eax
		add	esp, 08h*04h
		add	edi, SIZE SEGDATA_PROCEDURE
		dec	[cProcedures_]							;decrease counter
		jnz	@P_SYMD_ProcDefLoop

;edx has number of local variables in all procedure
		test	edx, edx
		jz	@P_SYMD_NoLocalVariables
.data
sP_SYMD_LocalDefS	db 13,10,"Local variables definitions:",13,10,0
sP_SYMD_LocalDef	db"[file offset: %x]",13,10
				db"   offset    data      name",13,10
				db"   0         SHORT     %2x (ten)",13,10
				db"   2         SHORT     %2x (tableType)",13,10
				db"   4         ULONG     %x (type)",13,10
				db"   8         ULONG     %x (iNameLocal) [%s]",13,10
				db"   C         ULONG     %x offLocal",13,10,0
.code
		call	StringComplete, offset sP_SYMD_LocalDefS, eax
		mov	edi, ebx
		add	edi, [(SEGMENTDATA ptr ebx).offLVarDef]
		push	ebx							;I need a variable
@P_SYMD_LocalVarLoop1:
		push	dword ptr [(SEGDATA_VLPTABLE ptr edi).offVLP]
		mov	ecx, [(SEGDATA_VLPTABLE ptr edi).iNameVLP]
			mov	ebx, [nms.pNameOffsets]
			mov	ebx, [ebx+ecx*4]
			add	ebx, [nms.pStrings]
			push	ebx
		push	ecx
		push	dword ptr [(SEGDATA_VLPTABLE ptr edi).type_VLP]
		movzx ecx, word ptr [(SEGDATA_VLPTABLE ptr edi).tableType] 
		push	ecx
		movzx ecx, word ptr [(SEGDATA_VLPTABLE ptr edi).ten]
		push	ecx
;offset in file
		mov	ecx, edi
		sub	ecx, esi
		push	ecx
		call	StringComplete, offset sP_SYMD_LocalDef, eax
		add	esp, 07h*04h
		add	edi, SIZE SEGDATA_VLPTABLE
		dec	edx
		jnz	@P_SYMD_LocalVarLoop1
		pop	ebx

@P_SYMD_NoLocalVariables:

		cmp	[(SEGMENTDATA ptr ebx).cSourceSec], NULL		;number of sourceSections
		jz	@P_SYMD_NoSourceSection
.data
sP_SYMD_SourceCodeLineS	db 13,10,"Source code lines definitions [file offset: %x]:",13,10
					db"   offsetInCode   lineNumber",13,10,0
sP_SYMD_SourceCodeLine	db"   %x       %x",13,10,0
.code
;eax=pointer to 1st free byte in textBuffer
;ebx=points to current SEGMENTDATA structure
;edx=cLineTables
;esi=pNMSFileMapped [nms.hMapped]
;edi=pointer to current LineOffsetTable
		mov	edx, ebx
		add	edx, [(SEGMENTDATA ptr ebx).offSourceSDef]		;pointer to next segment variable data section
		mov	edx, [(SEGDATA_SOURCESECTION ptr edx).cLinesTables]
		mov	edi, ebx
		add	edi, [(SEGMENTDATA ptr ebx).offSCLineDef]		;pointer sourceCode line offsets
;offset in file
		mov	ecx, edi
		sub	ecx, esi
		push	ecx
		call	StringComplete, offset sP_SYMD_SourceCodeLineS, eax
		add	esp, 01h*04h
@P_SYMD_SourceLinesLoop:
		push	dword ptr [(SEGDATA_SOURCELINES ptr edi).lineNumber]
		push	dword ptr [(SEGDATA_SOURCELINES ptr edi).offInCode]
		add	edi, SIZE SEGDATA_SOURCELINES
		call	StringComplete, offset sP_SYMD_SourceCodeLine, eax
		add	esp, 02h*04h
		dec	edx
		jnz	@P_SYMD_SourceLinesLoop

.data
sP_SYMD_SourceSectionS	db 13,10,"Source section definition:",13,10,0
sP_SYMD_SourceSection	db"  [file offset: %x]",13,10
					db"     offset    data      name",13,10
					db"     0         ULONG     %x (offStartSourceSection)",13,10
					db"     4         ULONG     %x (offEndSourceSection)",13,10
					db"     8         ULONG     %x (offSourceLine)",13,10
					db"     C         ULONG     %x (cLinesTables)",13,10
					db"     10        ULONG     %x (offInSFDef)",13,10,0
.code
@P_SYMD_NoSourceCodeLines:
;eax=pointer to 1st free byte in textBuffer
;ebx=points to current SEGMENTDATA structure
;edx=cSourceSec
;esi=pNMSFileMapped [nms.hMapped]
;edi=pointer to current LineOffsetTable
		mov	edi, ebx
		add	edi, [(SEGMENTDATA ptr ebx).offSourceSDef]
		mov	edx, [(SEGMENTDATA ptr ebx).cSourceSec]
		call	StringComplete, offset sP_SYMD_SourceSectionS, eax
@P_SYMD_SourceSectionsLoop:
		push	dword ptr [(SEGDATA_SOURCESECTION ptr edi).offInSFDef]
		push	dword ptr [(SEGDATA_SOURCESECTION ptr edi).cLinesTables]
		push	dword ptr [(SEGDATA_SOURCESECTION ptr edi).offSourceLine]
		push	dword ptr [(SEGDATA_SOURCESECTION ptr edi).offEndSourceSection]
		push	dword ptr [(SEGDATA_SOURCESECTION ptr edi).offStartSourceSection]
;offset in file
		mov	ecx, edi
		sub	ecx, esi
		push	ecx
		call	StringComplete, offset sP_SYMD_SourceSection, eax
		add	edi, SIZE SEGDATA_SOURCESECTION
		add	esp, 06h*04h
		dec	edx
		jnz	@P_SYMD_SourceSectionsLoop

;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@P_SYMD_NoSourceSection:
@P_SYMD_NoProceduresInSegment:
		mov	ecx, [(SEGMENTDATA ptr ebx).cVLP]
		cmp	ecx, 0FFFFFFFFh			;are there any Variables/Labels/Procedures offsets def in this segment
		jz	@P_SYMD_NoVLPInSegment		;BORLAND
		cmp	ecx, NULL
		jz	@P_SYMD_NoVLPInSegment		;MASM
.data
sP_SYMD_VLPS		db 13,10,"Variable/Label/Procedure Offset Definitions:",13,10,0
sP_SYMD_VLP		db"[file offset: %x]",13,10
				db"   offset    data      name",13,10
				db"   0         SHORT     %2x (10h)",13,10
				db"   2         SHORT     %2x (tableType) [%s]",13,10
				db"   4         ULONG     %x (type)",13,10
				db"   8         ULONG     %x (iNameVLP) [%s]",13,10
				db"   C         ULONG     %x (offVLP)",13,10,0
;TableTypeStrings
@TableTypeS1		db"Procedure Local Variable (used in 'Local variable table')",0
;@TableTypeS2		db"Unknown",0
;@TableTypeS3		db"Unknown",0
@TableTypeS4		db"Label",0
@TableTypeS5		db"Variable",0
@TableTypeS6		db"Global Variable",0
@TableTypeS7		db"Local Procedure",0
@TableTypeS8		db"Global Procedure",0
@TableTypeS9		db"Import Descriptor (Don't take me for my word with this one.)",0
@TableTypeSUnknown	db"Unknown",0

TableType:
	DWORD offset @TableTypeSUnknown
	DWORD offset @TableTypeS1
	DWORD offset @TableTypeSUnknown
	DWORD offset @TableTypeSUnknown
	DWORD offset @TableTypeS4
	DWORD offset @TableTypeS5
	DWORD offset @TableTypeS6
	DWORD offset @TableTypeS7
	DWORD offset @TableTypeS8
	DWORD offset @TableTypeS9
;END TableType

sP_SYMD_VLPOffsetsS	db 13,10,"Variable/Label/Procedure Offsets: (if this offsets aren't  k*10h, then please contact me)",13,10
				db"   offset",13,10,0
sP_SYMD_VLPOffsets	db"   %x",13,10,0

.code
;eax=pointer to 1st free byte in textBuffer
;ebx=points to current SEGMENTDATA structure
;edx=cVLP
;esi=pNMSFileMapped [nms.hMapped]
;edi=pointer to VLP tables
		call	StringComplete, offset sP_SYMD_VLPS, eax
		mov	edi, ebx
		add	edi, [(SEGMENTDATA ptr ebx).offVLPDef]
		mov	edx, [(SEGMENTDATA ptr ebx).cVLP]
		push	ebx					;I need another variable
@P_SYMD_VLPLoop:
		push	dword ptr [(SEGDATA_VLPTABLE ptr edi).offVLP]
		mov	ecx, [(SEGDATA_VLPTABLE ptr edi).iNameVLP]
			mov	ebx, [nms.pNameOffsets]
			mov	ebx, [ebx+ecx*4]
			add	ebx, [nms.pStrings]
			push	ebx
		push	ecx
		push	dword ptr [(SEGDATA_VLPTABLE ptr edi).type_VLP]
		movzx ecx, word ptr [(SEGDATA_VLPTABLE ptr edi).tableType]
		cmp	ecx, 9
		jbe	@P_SYMD_VLP_Proceed
		xor	ecx, ecx
@P_SYMD_VLP_Proceed:
		push	dword ptr [offset TableType + 4*ecx]
		push	ecx
		movzx ebx, word ptr [(SEGDATA_VLPTABLE ptr edi).ten]
		push	ebx
;offset in file
		mov	ecx, edi
		sub	ecx, esi
		push	ecx
		call	StringComplete, offset sP_SYMD_VLP, eax
		add	edi, SIZE SEGDATA_VLPTABLE
		add	esp, 08h*04h
		dec	edx
		jnz	@P_SYMD_VLPLoop
		pop	ebx
;offsets
		call	StringComplete, offset sP_SYMD_VLPOffsetsS, eax
		mov	edi, ebx
		add	edi, [(SEGMENTDATA ptr ebx).offVLPOffsets]
		mov	edx, [(SEGMENTDATA ptr ebx).cVLP]

@P_SYMD_VLPOffsetsLoop:
		push	dword ptr [edi]
		add	edi, 04h
		call	StringComplete, offset sP_SYMD_VLPOffsets, eax
		add	esp, 01h*04h
		dec	edx
		jnz	@P_SYMD_VLPOffsetsLoop

;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@P_SYMD_NoVLPInSegment:
		mov	ecx, [cSegmentsCurrent]
		mov	edx, [pSegmentDataHeader]
		inc	ecx
		cmp	ecx, [(SEGMENTDATA_HEADER ptr edx).cSegments]
		mov	[cSegmentsCurrent], ecx
		jb	@P_SYMD_SegLoop
		ret
ENDP

Procedure_SRCP PROC pEntry_:POINTER
.data
sP_SRCP		db 13,10,"Numbers in SRCP section:",13,10,13,10
			db"offset  data     name",13,10
			db"0       ULONG    SRCP(string)",13,10
			db"4       ULONG    sectionLenght",13,10
			db"8       ULONG    %x (pSourceFiles)",13,10
			db"C       ULONG    %x",13,10
			db"10      ULONG    %x",13,10,0
.code
		mov	edi, pEntry_
		add	edi, [nms.hMapped]

		push	dword ptr [(SRCP_HEADER ptr edi).N2_SRCP]
		push	dword ptr [(SRCP_HEADER ptr edi).N1_SRCP]
		push	dword ptr [(SRCP_HEADER ptr edi).offSourceFiles]
		call	StringComplete, offset sP_SRCP, eax
		add	esp, 03h*04h
		ret
ENDP

Procedure_FPOD PROC pEntry_:POINTER
.data
sP_FPOD		db 13,10,"FPOD Header:",13,10,13,10
			db"offset  data     name",13,10
			db"0       ULONG    FPOD(string)",13,10
			db"4       ULONG    sectionLenght",13,10
			db"8       ULONG    %x",13,10
			db"C       ULONG    %x",13,10
			db"10      ULONG    %x",13,10
			db"14      ULONG    %x",13,10
			db"18      ULONG    %x",13,10
			db"1C      ULONG    %x",13,10
			db"20      ULONG    %x",13,10
			db"24      ULONG    %x",13,10
			db"28      ULONG    %x",13,10
			db"2C      ULONG    %x",13,10,0
.code
		mov	edi, pEntry_
		add	edi, [nms.hMapped]

		push	dword ptr [(FPOD_HEADER ptr edi).NA_FPOD]
		push	dword ptr [(FPOD_HEADER ptr edi).N9_FPOD]
		push	dword ptr [(FPOD_HEADER ptr edi).N8_FPOD]
		push	dword ptr [(FPOD_HEADER ptr edi).N7_FPOD]
		push	dword ptr [(FPOD_HEADER ptr edi).N6_FPOD]
		push	dword ptr [(FPOD_HEADER ptr edi).N5_FPOD]
		push	dword ptr [(FPOD_HEADER ptr edi).N4_FPOD]
		push	dword ptr [(FPOD_HEADER ptr edi).N3_FPOD]
		push	dword ptr [(FPOD_HEADER ptr edi).N2_FPOD]
		push	dword ptr [(FPOD_HEADER ptr edi).N1_FPOD]
		call	StringComplete, offset sP_FPOD, eax
		add	esp, 0Ah*04h
		ret
ENDP

End Main

