user: Translate the below assembly code into C programming language:

```asm
<MD4_Final>:
  endbr64
  push   %r14
  mov    $0x80,%ecx
  push   %r13
  push   %r12
  mov    %rdi,%r12
  push   %rbp
  push   %rbx
  mov    0x8(%rsi),%edx
  mov    %rsi,%rbx
  mov    (%rsi),%r13
  mov    %edx,%eax
  sar    $0x2,%eax
  movslq %eax,%rdi
  shl    $0x3,%rdi
  lea    0x0(%r13,%rdi,1),%r8
  and    $0x3,%edx
  je     L48
  mov    (%r8),%rsi
  mov    %rsi,%rcx
  or     $0x800000,%rcx
  cmp    $0x2,%edx
  je     L48
  mov    %rsi,%rcx
  bts    $0x1f,%rcx
  cmp    $0x3,%edx
  jne    L27
L48:
  mov    D5(%rip),%r14
  add    $0x1,%eax
  mov    %rcx,(%r8)
  movslq (%r14),%rbp
  lea    -0x1(%rbp),%edx
  cmp    %eax,%edx
  jg     L7
  cmp    %eax,%ebp
  jg     L32
L49:
  mov    $0x1,%edx
  mov    %r13,%rsi
  mov    %rbx,%rdi
  call   <md4_block_host_order@plt>
  movslq (%r14),%rbp
  xor    %eax,%eax
L7:
  lea    -0x2(%rbp),%edx
  cmp    %edx,%eax
  jge    L23
  lea    -0x3(%rbp),%edx
  xor    %esi,%esi
  sub    %eax,%edx
  cltq
  lea    0x8(,%rdx,8),%rdx
  lea    0x0(%r13,%rax,8),%rdi
  call   <memset@plt>
L23:
  mov    0x10(%rbx),%rax
  shl    $0x3,%rbp
  mov    %r13,%rsi
  mov    %rbx,%rdi
  mov    $0x1,%edx
  mov    %rax,-0x10(%r13,%rbp,1)
  mov    0x18(%rbx),%rax
  mov    %rax,-0x8(%r13,%rbp,1)
  call   <md4_block_host_order@plt>
  mov    0x20(%rbx),%eax
  mov    %eax,(%r12)
  mov    0x28(%rbx),%eax
  mov    %eax,0x4(%r12)
  mov    0x30(%rbx),%eax
  mov    %eax,0x8(%r12)
  mov    0x38(%rbx),%eax
  mov    %eax,0xc(%r12)
  mov    $0x1,%eax
  movl   $0x0,0x8(%rbx)
  pop    %rbx
  pop    %rbp
  pop    %r12
  pop    %r13
  pop    %r14
  ret
  cs nopw 0x0(%rax,%rax,1)
L27:
  or     $0x8000,%rsi
  mov    $0x80,%ecx
  cmp    $0x1,%edx
  cmove  %rsi,%rcx
  jmp    L48
  nopl   0x0(%rax,%rax,1)
L32:
  movq   $0x0,0x8(%r13,%rdi,1)
  jmp    L49
```

assistant: ```c
int MD4_Final(unsigned char *md, MD4_CTX *c) {
  register MD4_LONG *p;
  register unsigned long l;
  register int i, j;
  static const unsigned char end[4] = {0x80, 0x00, 0x00, 0x00};
  const unsigned char *cp = end;
  p = c->data;
  i = c->num >> 2;
  j = c->num & 0x03;
  l = (j == 0) ? 0 : p[i];
  {
    switch (j) {
    case 0:
      l = ((unsigned long)(*((cp)++)));
    case 1:
      l |= ((unsigned long)(*((cp)++))) << 8;
    case 2:
      l |= ((unsigned long)(*((cp)++))) << 16;
    case 3:
      l |= ((unsigned long)(*((cp)++))) << 24;
    }
  };
  p[i++] = l;
  if (i > (MD4_LBLOCK - 2)) {
    if (i < MD4_LBLOCK)
      p[i] = 0;
    md4_block_host_order(c, p, 1);
    i = 0;
  }
  for (; i < (MD4_LBLOCK - 2); i++)
    p[i] = 0;
  p[MD4_LBLOCK - 2] = c->Nl;
  p[MD4_LBLOCK - 1] = c->Nh;
  md4_block_host_order(c, p, 1);
  do {
    unsigned long ll;
    ll = (c)->A;
    (*(((md))++) = (unsigned char)(((ll)) & 0xff), *(((md))++) = (unsigned char)(((ll) >> 8) & 0xff), *(((md))++) = (unsigned char)(((ll) >> 16) & 0xff), *(((md))++) = (unsigned char)(((ll) >> 24) & 0xff), ll);
    ll = (c)->B;
    (*(((md))++) = (unsigned char)(((ll)) & 0xff), *(((md))++) = (unsigned char)(((ll) >> 8) & 0xff), *(((md))++) = (unsigned char)(((ll) >> 16) & 0xff), *(((md))++) = (unsigned char)(((ll) >> 24) & 0xff), ll);
    ll = (c)->C;
    (*(((md))++) = (unsigned char)(((ll)) & 0xff), *(((md))++) = (unsigned char)(((ll) >> 8) & 0xff), *(((md))++) = (unsigned char)(((ll) >> 16) & 0xff), *(((md))++) = (unsigned char)(((ll) >> 24) & 0xff), ll);
    ll = (c)->D;
    (*(((md))++) = (unsigned char)(((ll)) & 0xff), *(((md))++) = (unsigned char)(((ll) >> 8) & 0xff), *(((md))++) = (unsigned char)(((ll) >> 16) & 0xff), *(((md))++) = (unsigned char)(((ll) >> 24) & 0xff), ll);
  } while (0);
  c->num = 0;
  return 1;
}
```