%include "util.mac"
%include "icedump.inc"
%include "vxdn.inc"
%include "wiat.inc"


global Parse_Load
global Service_Load


extern sdata
extern Parser.error
extern Parser.errorMsg
extern SetCB
extern IsPageCommitted
extern ParseAddress
extern ParseExpression


bits 32


;-------------------------------------------------------------------------------
; LOAD <address> <length> <file name>
;-------------------------------------------------------------------------------
segment _LTEXT
Parse_Load:
	push	byte SERVICE_LOAD
	mov	ebp,[dClient_EAX]
	pop	dword [ebp]

	mov	edi,.Error_BadAddress
	call	ParseAddress		; parse <address>
	jb	near Parser.errorMsg

	mov	ebp,[dClient_EDI]	; store start address of block
	mov	[ebp],eax

	mov	edi,.Error_NoLength
	call	[pSkipWhiteSpace]	; skip to <length>
	jz	near Parser.errorMsg

	mov	edi,.Error_BadLength
	call	ParseExpression		; parse <length>
	jb	near Parser.errorMsg

	mov	ebp,[dClient_ECX]	; store length of block
	mov	[ebp],eax

	mov	edi,.Error_NoFile
	call	[pSkipWhiteSpace]	; skip to <file name>
	jz	near Parser.errorMsg

	mov	ebp,[dClient_ESI]	; store pointer to file name
	mov	[ebp],esi

	call	SetCB

	mov     ebp,[fExecuteMoreCommands]	; set internal Winice flag to 0
	mov	byte [ebp],0

	popad
	retn


segment _LDATA
.Error_BadAddress	db 'invalid address.',0
.Error_NoLength		db 'specify length.',0
.Error_BadLength	db 'invalid length.',0
.Error_NoFile		db 'specify filename.',0


;-------------------------------------------------------------------------------
; this is the actual file loader code that's executed in ring-0.
;-------------------------------------------------------------------------------
segment _LTEXT
Service_Load:
	mov	esi,[ebp+CRS.ESI]	; get pointer to file name
	mov	eax,R0_OPENCREAT_IN_CONTEXT
	mov	ebx,0x2040		; read only|share:deny none|no INT24
;	mov	ecx,0x20		; archive
	movzx	ecx,bh
	mov	edx,0x01		; open|fail
	VxDCall IFSMgr_Ring0_FileIO
	jb	.return

	mov	ebx,eax			; store file handle
	mov	esi,[ebp+CRS.EDI]	; get start address of block

.loop:
	mov	edi,esi
	shr	edi,12			; get current page number
	mov	eax,edi			; save page number for later use
	inc	edi			; get next page number
	shl	edi,12			; get linear start address of next page
	sub	edi,esi			; get length of block on current page
	mov	ecx,[ebp+CRS.ECX]	; get remaining length
	cmp	edi,ecx			; EDI: bytes to read into current page
	ja	@F

	mov	ecx,edi			; dump from one page at a time

@@
	call	IsPageCommitted
	jz	.skipPage

	mov	al,[esi]		; PAGEIN!

	mov	eax,R0_READFILE_IN_CONTEXT
	push	ebx			; save file handle
	mov	edx,esi
	sub	edx,[ebp+CRS.EDI]	; EDX: absolute file pointer
	VxDCall IFSMgr_Ring0_FileIO
	pop	ebx			; restore file handle
	jb	.close

	mov	ecx,eax			; never seen them being different...

	debug_start debugflags, ICEDUMP_DEBUG_FILEIO
	Trace_Out "ICEDUMP: R0_READ eax:#eax ecx:#ecx"
	debug_end

.skipPage:
	add	esi,ecx
	sub	[ebp+CRS.ECX],ecx	; are we done?
	jnz	.loop

.close:
	mov	eax,R0_CLOSEFILE
	VxDCall IFSMgr_Ring0_FileIO

.return:
	popfd
	popad
	retn				; client will return to an INT3
