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

```asm
<utf_last_valid2>:
  endbr64
  push   %rbp
  mov    %rsp,%rbp
  mov    %rdi,-0x28(%rbp)
  mov    %esi,-0x2c(%rbp)
  mov    -0x28(%rbp),%rax
  mov    %rax,-0x10(%rbp)
  mov    -0x2c(%rbp),%eax
  movslq %eax,%rdx
  mov    -0x28(%rbp),%rax
  add    %rdx,%rax
  mov    %rax,-0x8(%rbp)
  movl   $0x0,-0x14(%rbp)
  jmp    L331
L336:
  mov    -0x28(%rbp),%rax
  lea    0x1(%rax),%rdx
  mov    %rdx,-0x28(%rbp)
  movzbl (%rax),%eax
  mov    %al,-0x15(%rbp)
  cmpl   $0x7,-0x14(%rbp)
  ja     L307
  mov    -0x14(%rbp),%eax
  lea    0x0(,%rax,4),%rdx
  lea    D10(%rip),%rax
  mov    (%rdx,%rax,1),%eax
  cltq
  lea    D10(%rip),%rdx
  add    %rdx,%rax
  notrack jmp *%rax
  movzbl -0x15(%rbp),%eax
  test   %al,%al
  jns    L88
  cmpb   $0xc1,-0x15(%rbp)
  ja     L218
  movl   $0x8,-0x14(%rbp)
  jmp    L63
L218:
  cmpb   $0xdf,-0x15(%rbp)
  ja     L17
  movl   $0x1,-0x14(%rbp)
  jmp    L63
L17:
  cmpb   $0xe0,-0x15(%rbp)
  jne    L98
  movl   $0x2,-0x14(%rbp)
  jmp    L63
L98:
  cmpb   $0xec,-0x15(%rbp)
  ja     L359
  movl   $0x3,-0x14(%rbp)
  jmp    L63
L359:
  cmpb   $0xed,-0x15(%rbp)
  jne    L71
  movl   $0x4,-0x14(%rbp)
  jmp    L63
L71:
  cmpb   $0xef,-0x15(%rbp)
  ja     L464
  movl   $0x3,-0x14(%rbp)
  jmp    L63
L464:
  cmpb   $0xf0,-0x15(%rbp)
  jne    L402
  movl   $0x5,-0x14(%rbp)
  jmp    L63
L402:
  cmpb   $0xf3,-0x15(%rbp)
  ja     L203
  movl   $0x6,-0x14(%rbp)
  jmp    L63
L203:
  cmpb   $0xf4,-0x15(%rbp)
  ja     L281
  movl   $0x7,-0x14(%rbp)
  jmp    L63
L281:
  movl   $0x8,-0x14(%rbp)
  jmp    L63
  movzbl -0x15(%rbp),%eax
  test   %al,%al
  jns    L418
  cmpb   $0xbf,-0x15(%rbp)
  ja     L418
  movl   $0x0,-0x14(%rbp)
  jmp    L63
L418:
  movl   $0x8,-0x14(%rbp)
  jmp    L63
  cmpb   $0x9f,-0x15(%rbp)
  jbe    L512
  cmpb   $0xbf,-0x15(%rbp)
  ja     L512
  movl   $0x1,-0x14(%rbp)
  jmp    L63
L512:
  movl   $0x8,-0x14(%rbp)
  jmp    L63
  movzbl -0x15(%rbp),%eax
  test   %al,%al
  jns    L146
  cmpb   $0xbf,-0x15(%rbp)
  ja     L146
  movl   $0x1,-0x14(%rbp)
  jmp    L63
L146:
  movl   $0x8,-0x14(%rbp)
  jmp    L63
  movzbl -0x15(%rbp),%eax
  test   %al,%al
  jns    L101
  cmpb   $0x9f,-0x15(%rbp)
  ja     L101
  movl   $0x1,-0x14(%rbp)
  jmp    L63
L101:
  movl   $0x8,-0x14(%rbp)
  jmp    L63
  cmpb   $0x8f,-0x15(%rbp)
  jbe    L92
  cmpb   $0xbf,-0x15(%rbp)
  ja     L92
  movl   $0x3,-0x14(%rbp)
  jmp    L63
L92:
  movl   $0x8,-0x14(%rbp)
  jmp    L63
  movzbl -0x15(%rbp),%eax
  test   %al,%al
  jns    L365
  cmpb   $0xbf,-0x15(%rbp)
  ja     L365
  movl   $0x3,-0x14(%rbp)
  jmp    L63
L365:
  movl   $0x8,-0x14(%rbp)
  jmp    L63
  movzbl -0x15(%rbp),%eax
  test   %al,%al
  jns    L177
  cmpb   $0x8f,-0x15(%rbp)
  ja     L177
  movl   $0x3,-0x14(%rbp)
  jmp    L63
L177:
  movl   $0x8,-0x14(%rbp)
  jmp    L63
L307:
  mov    -0x10(%rbp),%rax
  jmp    L152
L88:
  nop
L63:
  cmpl   $0x0,-0x14(%rbp)
  jne    L331
  mov    -0x28(%rbp),%rax
  mov    %rax,-0x10(%rbp)
L331:
  mov    -0x28(%rbp),%rax
  cmp    -0x8(%rbp),%rax
  jb     L336
  mov    -0x10(%rbp),%rax
L152:
  pop    %rbp
  ret
```

assistant: ```c
const char *utf_last_valid2(const char *data, int len) {
  const char *start = data, *end = data + len;
  int state = 0;
  while (data < end) {
    unsigned char octet = *data++;
    switch (state) {
    case 0:
      if (octet <= 0x7F)
        break;
      else if (octet <= 0xC1)
        state = 8;
      else if (octet <= 0xDF)
        state = 1;
      else if (octet == 0xE0)
        state = 2;
      else if (octet <= 0xEC)
        state = 3;
      else if (octet == 0xED)
        state = 4;
      else if (octet <= 0xEF)
        state = 3;
      else if (octet == 0xF0)
        state = 5;
      else if (octet <= 0xF3)
        state = 6;
      else if (octet <= 0xF4)
        state = 7;
      else
        state = 8;
      break;
    case 1:
      if (octet >= 0x80 && octet <= 0xBF)
        state = 0;
      else
        state = 8;
      break;
    case 2:
      if (octet >= 0xA0 && octet <= 0xBF)
        state = 1;
      else
        state = 8;
      break;
    case 3:
      if (octet >= 0x80 && octet <= 0xBF)
        state = 1;
      else
        state = 8;
      break;
    case 4:
      if (octet >= 0x80 && octet <= 0x9F)
        state = 1;
      else
        state = 8;
      break;
    case 5:
      if (octet >= 0x90 && octet <= 0xBF)
        state = 3;
      else
        state = 8;
      break;
    case 6:
      if (octet >= 0x80 && octet <= 0xBF)
        state = 3;
      else
        state = 8;
      break;
    case 7:
      if (octet >= 0x80 && octet <= 0x8F)
        state = 3;
      else
        state = 8;
      break;
    default:
    case 8:
      return start;
    }
    if (state == 0)
      start = data;
  }
  return start;
}
```