// File: williewillus[P]panda_scratchpad/src/wrapper/DiskMod.cpp
// Function: wrapper::DiskMod::Deserialize(std::shared_ptr<char>, wrapper::DiskMod&)
int DiskMod::Deserialize(shared_ptr<char> data, DiskMod &res) {
  res.Reset();

  // Skip the first uint64 which is the size of this region. This is a blind
  // deserialization of the object!
  char *data_ptr = data.get();
  data_ptr += sizeof(uint64_t);

  uint16_t mod_type;
  uint16_t mod_opts;
  memcpy(&mod_type, data_ptr, sizeof(uint16_t));
  data_ptr += sizeof(uint16_t);
  res.mod_type = (DiskMod::ModType) be16toh(mod_type);

  memcpy(&mod_opts, data_ptr, sizeof(uint16_t));
  data_ptr += sizeof(uint16_t);
  res.mod_opts = (DiskMod::ModOpts) be16toh(mod_opts);

  if (res.mod_type == DiskMod::kCheckpointMod ||
    res.mod_type == DiskMod::kSyncMod) {
    // No more left to do here.
    return 0;
  }

  // Small buffer to read characters into so we aren't adding to a string one
  // character at a time until the end of the string.
  const unsigned int tmp_size = 128;
  char tmp[tmp_size];
  memset(tmp, 0, tmp_size);
  unsigned int chars_read = 0;
  while (data_ptr[0] != '\0') {
    // We still haven't seen a null terminator, so read another character.
    tmp[chars_read] = data_ptr[0];
    ++chars_read;
    if (chars_read == tmp_size - 1) {
      // Fall into this at one character short so that we have an automatic null
      // terminator
      res.path += tmp;
      chars_read = 0;
      // Required because we just add the char[] to the string and we don't want
      // extra junk. An alternative would be to make sure you always had a null
      // terminator the character after the one that was just assigned.
      memset(tmp, 0, tmp_size);
    }
    ++data_ptr;
  }
  // Add the remaining data that is in tmp.
  res.path += tmp;
  // Move past the null terminating character.
  ++data_ptr;

  res.directory_mod = (bool) data_ptr[0];
  ++data_ptr;

  if (res.mod_type == DiskMod::kFsyncMod ||
      res.mod_type == DiskMod::kCreateMod) {
    return 0;
  }

  uint64_t file_mod_location;
  uint64_t file_mod_len;
  memcpy(&file_mod_location, data_ptr, sizeof(uint64_t));
  data_ptr += sizeof(uint64_t);
  file_mod_location = be64toh(file_mod_location);
  res.file_mod_location = file_mod_location;

  memcpy(&file_mod_len, data_ptr, sizeof(uint64_t));
  data_ptr += sizeof(uint64_t);
  file_mod_len = be64toh(file_mod_len);
  res.file_mod_len = file_mod_len;

  // Some mods have file length and location, but no actual data associated with
  // them.
  if (res.mod_type == DiskMod::kSyncFileRangeMod ||
      res.mod_opts == DiskMod::kFallocateOpt ||
      res.mod_opts == DiskMod::kFallocateKeepSizeOpt ||
      res.mod_opts == DiskMod::kPunchHoleKeepSizeOpt ||
      res.mod_opts == DiskMod::kCollapseRangeOpt ||
      res.mod_opts == DiskMod::kZeroRangeOpt ||
      res.mod_opts == DiskMod::kZeroRangeKeepSizeOpt ||
      res.mod_opts == DiskMod::kInsertRangeOpt) {
    return 0;
  }

  if (res.file_mod_len > 0) {
    // Read the data for this mod.
    res.file_mod_data.reset(new (std::nothrow) char[res.file_mod_len],
        [](char *c) {delete[] c;});
    if (res.file_mod_data.get() == nullptr) {
      return -1;
    }
    memcpy(res.file_mod_data.get(), data_ptr, res.file_mod_len);
  }

  return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xe0, %rsp
movq %rdi, -0xd8(%rbp)
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movq -0x18(%rbp), %rdi
callq 0xe580
movq -0xd8(%rbp), %rdi
callq 0xf430
movq %rax, -0x20(%rbp)
movq -0x20(%rbp), %rax
addq $0x8, %rax
movq %rax, -0x20(%rbp)
movq -0x20(%rbp), %rax
movw (%rax), %ax
movw %ax, -0x22(%rbp)
movq -0x20(%rbp), %rax
addq $0x2, %rax
movq %rax, -0x20(%rbp)
movzwl -0x22(%rbp), %edi
callq 0xe230
movzwl %ax, %ecx
movq -0x18(%rbp), %rax
movl %ecx, 0x20(%rax)
movq -0x20(%rbp), %rax
movw (%rax), %ax
movw %ax, -0x24(%rbp)
movq -0x20(%rbp), %rax
addq $0x2, %rax
movq %rax, -0x20(%rbp)
movzwl -0x24(%rbp), %edi
callq 0xe230
movzwl %ax, %ecx
movq -0x18(%rbp), %rax
movl %ecx, 0x24(%rax)
movq -0x18(%rbp), %rax
cmpl $0x6, 0x20(%rax)
je 0xe307
movq -0x18(%rbp), %rax
cmpl $0x8, 0x20(%rax)
jne 0xe313
movl $0x0, -0x4(%rbp)
jmp 0xe574
movl $0x80, -0x28(%rbp)
leaq -0xb0(%rbp), %rdi
xorl %esi, %esi
movl $0x80, %edx
callq 0x6310
movl $0x0, -0xb4(%rbp)
movq -0x20(%rbp), %rax
movsbl (%rax), %eax
cmpl $0x0, %eax
je 0xe3a9
movq -0x20(%rbp), %rax
movb (%rax), %cl
movl -0xb4(%rbp), %eax
movb %cl, -0xb0(%rbp,%rax)
movl -0xb4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xb4(%rbp)
cmpl $0x7f, -0xb4(%rbp)
jne 0xe39b
leaq -0xb0(%rbp), %rsi
movq -0x18(%rbp), %rdi
callq 0x6510
movl $0x0, -0xb4(%rbp)
leaq -0xb0(%rbp), %rdi
xorl %esi, %esi
movl $0x80, %edx
callq 0x6310
movq -0x20(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x20(%rbp)
jmp 0xe337
leaq -0xb0(%rbp), %rsi
movq -0x18(%rbp), %rdi
callq 0x6510
movq -0x20(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x20(%rbp)
movq -0x20(%rbp), %rax
cmpb $0x0, (%rax)
setne %cl
movq -0x18(%rbp), %rax
andb $0x1, %cl
movb %cl, 0xb8(%rax)
movq -0x20(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x20(%rbp)
movq -0x18(%rbp), %rax
cmpl $0x7, 0x20(%rax)
je 0xe3fc
movq -0x18(%rbp), %rax
cmpl $0x0, 0x20(%rax)
jne 0xe408
movl $0x0, -0x4(%rbp)
jmp 0xe574
movq -0x20(%rbp), %rax
movq (%rax), %rax
movq %rax, -0xc0(%rbp)
movq -0x20(%rbp), %rax
addq $0x8, %rax
movq %rax, -0x20(%rbp)
movq -0xc0(%rbp), %rdi
callq 0xdf10
movq %rax, -0xc0(%rbp)
movq -0xc0(%rbp), %rcx
movq -0x18(%rbp), %rax
movq %rcx, 0xd0(%rax)
movq -0x20(%rbp), %rax
movq (%rax), %rax
movq %rax, -0xc8(%rbp)
movq -0x20(%rbp), %rax
addq $0x8, %rax
movq %rax, -0x20(%rbp)
movq -0xc8(%rbp), %rdi
callq 0xdf10
movq %rax, -0xc8(%rbp)
movq -0xc8(%rbp), %rcx
movq -0x18(%rbp), %rax
movq %rcx, 0xd8(%rax)
movq -0x18(%rbp), %rax
cmpl $0x9, 0x20(%rax)
je 0xe4d6
movq -0x18(%rbp), %rax
cmpl $0x2, 0x24(%rax)
je 0xe4d6
movq -0x18(%rbp), %rax
cmpl $0x3, 0x24(%rax)
je 0xe4d6
movq -0x18(%rbp), %rax
cmpl $0x4, 0x24(%rax)
je 0xe4d6
movq -0x18(%rbp), %rax
cmpl $0x5, 0x24(%rax)
je 0xe4d6
movq -0x18(%rbp), %rax
cmpl $0x6, 0x24(%rax)
je 0xe4d6
movq -0x18(%rbp), %rax
cmpl $0x7, 0x24(%rax)
je 0xe4d6
movq -0x18(%rbp), %rax
cmpl $0x8, 0x24(%rax)
jne 0xe4e2
movl $0x0, -0x4(%rbp)
jmp 0xe574
movq -0x18(%rbp), %rax
cmpq $0x0, 0xd8(%rax)
jbe 0xe56d
movq -0x18(%rbp), %rax
addq $0xc0, %rax
movq %rax, -0xe0(%rbp)
movq -0x18(%rbp), %rax
movq 0xd8(%rax), %rdi
movq 0x26a75(%rip), %rsi     # 0x34f88
callq 0x6810
movq -0xe0(%rbp), %rdi
movq %rax, %rsi
callq 0xe600
movq -0x18(%rbp), %rdi
addq $0xc0, %rdi
callq 0xf430
cmpq $0x0, %rax
jne 0xe546
movl $0xffffffff, -0x4(%rbp) # imm = 0xFFFFFFFF
jmp 0xe574
movq -0x18(%rbp), %rdi
addq $0xc0, %rdi
callq 0xf430
movq %rax, %rdi
movq -0x20(%rbp), %rsi
movq -0x18(%rbp), %rax
movq 0xd8(%rax), %rdx
callq 0x6450
movl $0x0, -0x4(%rbp)
movl -0x4(%rbp), %eax
addq $0xe0, %rsp
popq %rbp
retq