// File: /workspace/github_c_makefile_star2_O1/lb3361[P]dosfs/ff.c
// Function: f_forward
FRESULT f_forward (
	FIL* fp, 						/* Pointer to the file object */
	UINT (*func)(const BYTE*,UINT),	/* Pointer to the streaming function */
	UINT btf,						/* Number of bytes to forward */
	UINT* bf						/* Pointer to number of bytes forwarded */
)
{
	FRESULT res;
	FATFS *fs;
	DWORD clst;
	LBA_t sect;
	FSIZE_t remain;
	UINT rcnt, csect;
	BYTE *dbuf;


	*bf = 0;	/* Clear transfer byte counter */
	res = validate(&fp->obj, &fs);		/* Check validity of the file object */
	if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res);
	if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED);	/* Check access mode */

	remain = fp->obj.objsize - fp->fptr;
	if (btf > remain) btf = (UINT)remain;			/* Truncate btf by remaining bytes */

	for ( ;  btf && (*func)(0, 0);					/* Repeat until all data transferred or stream goes busy */
		fp->fptr += rcnt, *bf += rcnt, btf -= rcnt) {
		csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1));	/* Sector offset in the cluster */
		if (fp->fptr % SS(fs) == 0) {				/* On the sector boundary? */
			if (csect == 0) {						/* On the cluster boundary? */
				clst = (fp->fptr == 0) ?			/* On the top of the file? */
					fp->obj.sclust : get_fat(&fp->obj, fp->clust);
				if (clst <= 1) ABORT(fs, FR_INT_ERR);
				if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR);
				fp->clust = clst;					/* Update current cluster */
			}
		}
		sect = clst2sect(fs, fp->clust);			/* Get current data sector */
		if (sect == 0) ABORT(fs, FR_INT_ERR);
		sect += csect;
#if FF_FS_TINY
		if (move_window(fs, sect) != FR_OK) ABORT(fs, FR_DISK_ERR);	/* Move sector window to the file data */
		dbuf = fs->win;
#else
		if (fp->sect != sect) {		/* Fill sector cache with file data */
#if !FF_FS_READONLY
			if (fp->flag & FA_DIRTY) {		/* Write-back dirty sector cache */
				if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);
				fp->flag &= (BYTE)~FA_DIRTY;
			}
#endif
			if (disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);
		}
		dbuf = fp->buf;
#endif
		fp->sect = sect;
		rcnt = SS(fs) - (UINT)fp->fptr % SS(fs);	/* Number of bytes remains in the sector */
		if (rcnt > btf) rcnt = btf;					/* Clip it by btr if needed */
		rcnt = (*func)(dbuf + ((UINT)fp->fptr % SS(fs)), rcnt);	/* Forward the file data */
		if (rcnt == 0) ABORT(fs, FR_INT_ERR);
	}

	LEAVE_FF(fs, FR_OK);
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x28, %rsp
movq %rcx, %r14
movl %edx, %ebp
movq %rsi, %r15
movq %rdi, %rbx
movl $0x0, (%rcx)
leaq 0x20(%rsp), %rsi
callq 0x67e1
movl %eax, %r12d
testl %eax, %eax
jne 0x9693
movzbl 0x31(%rbx), %r12d
testl %r12d, %r12d
jne 0x9693
movl $0x7, %r12d
testb $0x1, 0x30(%rbx)
je 0x9693
movq 0x10(%rbx), %r13
subq 0x38(%rbx), %r13
movl %ebp, %eax
cmpq %rax, %r13
cmovael %ebp, %r13d
testl %r13d, %r13d
je 0x9655
movq 0x20(%rsp), %rbp
leaq 0x60(%rbx), %rax
movq %rax, 0x10(%rsp)
xorl %r12d, %r12d
movq %rbp, 0x8(%rsp)
movq %r15, 0x18(%rsp)
xorl %edi, %edi
xorl %esi, %esi
callq *%r15
testl %eax, %eax
je 0x9693
movq 0x38(%rbx), %rax
movq %rax, %rcx
shrq $0x9, %rcx
movzwl 0xa(%rbp), %edx
decl %edx
movl %eax, %esi
andl $0x1ff, %esi            # imm = 0x1FF
andl %edx, %ecx
movl %ecx, %r15d
orq %r15, %rsi
jne 0x9583
testq %rax, %rax
je 0x956b
movl 0x40(%rbx), %esi
movq %rbx, %rdi
callq 0x6363
jmp 0x956e
movl 0xc(%rbx), %eax
cmpl $0x2, %eax
jb 0x9669
cmpl $-0x1, %eax
je 0x9678
movl %eax, 0x40(%rbx)
movl 0x40(%rbx), %eax
addl $-0x2, %eax
movl 0x28(%rbp), %ecx
addl $-0x2, %ecx
cmpl %ecx, %eax
jae 0x95a6
movzwl 0xa(%rbp), %ecx
movq %rbp, %rdx
movl %eax, %ebp
imulq %rcx, %rbp
addq 0x48(%rdx), %rbp
jmp 0x95a8
xorl %ebp, %ebp
movl $0x2, 0x4(%rsp)
movb $0x2, 0x3(%rsp)
testq %rbp, %rbp
je 0x9685
addq %r15, %rbp
movq 0x48(%rbx), %rdx
cmpq %rbp, %rdx
movq 0x18(%rsp), %r15
je 0x9614
cmpb $0x0, 0x30(%rbx)
jns 0x95f5
movq 0x8(%rsp), %rax
movzbl 0x1(%rax), %edi
movq 0x10(%rsp), %rsi
movl $0x1, %ecx
callq 0x2d47
testl %eax, %eax
jne 0x965a
andb $0x7f, 0x30(%rbx)
movq 0x8(%rsp), %rax
movzbl 0x1(%rax), %edi
movq 0x10(%rsp), %rsi
movq %rbp, %rdx
movl $0x1, %ecx
callq 0x2cd0
testl %eax, %eax
jne 0x965a
movq %rbp, 0x48(%rbx)
movq 0x38(%rbx), %rdi
andl $0x1ff, %edi            # imm = 0x1FF
movl $0x200, %esi            # imm = 0x200
subl %edi, %esi
cmpl %r13d, %esi
cmovael %r13d, %esi
addq 0x10(%rsp), %rdi
callq *%r15
testl %eax, %eax
je 0x9685
movl %eax, %ecx
addq %rcx, 0x38(%rbx)
addl %eax, (%r14)
subl %eax, %r13d
movq 0x8(%rsp), %rbp
jne 0x9527
jmp 0x9693
xorl %r12d, %r12d
jmp 0x9693
movb $0x1, 0x3(%rsp)
movl $0x1, 0x4(%rsp)
jmp 0x9685
movl $0x2, 0x4(%rsp)
movb $0x2, 0x3(%rsp)
jmp 0x9685
movl $0x1, 0x4(%rsp)
movb $0x1, 0x3(%rsp)
movb 0x3(%rsp), %al
movb %al, 0x31(%rbx)
movl 0x4(%rsp), %eax
movl %eax, %r12d
movl %r12d, %eax
addq $0x28, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq