/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include <cassert>
#include <cstring>
#include <fstream>
#include <iostream>
#include <string>

#include "se_defines.h"

SE_GLOBALS()

uint32_t crc32(const std::string& data) {
  uint32_t crc = 0xFFFFFFFF;
  for (char c : data) {
    crc ^= static_cast<unsigned char>(c);
    for (uint32_t j = 0; j < 8; ++j) {
      crc = (crc >> 1) ^ (0xEDB88320 & -(crc & 1));
    }
  }
  return ~crc;
}

uint8_t decode_char(char c) {
  if (c >= '0' && c <= '9') {
    return c - '0';
  }
  if (c >= 'a' && c <= 'f') {
    return c - 'a' + 10;
  }
  if (c >= 'A' && c <= 'F') {
    return c - 'A' + 10;
  }
  assert(false);
  return 0;
}

std::string decode(const std::string& content) {
  if (content.size() % 2 != 0) {
    return "";
  }
  std::string decoded;
  for (size_t i = 0; i < content.size(); i += 2) {
    decoded += decode_char(content[i]) * 16 + decode_char(content[i + 1]);
  }
  return decoded;
}

bool parse_content(const std::string& input) {
  std::string content = decode(input);
  if (content.size() <= 8) {
    return false;
  }
  SE_STEP(true);
  if (content.substr(0, 4) != "CRCC") {
    return false;
  }
  SE_STEP(true);
  uint32_t header_crc = 0;
  std::memcpy(&header_crc, content.c_str() + 4, 4);
  uint32_t content_crc = crc32(content.substr(8));
  printf("expected crc32 is %x, header got %x\n", content_crc, header_crc);
  if (header_crc != content_crc) {
    return false;
  }
  SE_STEP(true);
  if (content.substr(8) != "file_content") {
    return false;
  }
  SE_STEP(true);
  return true;
}

int main(int argc, char* argv[]) {
  std::istream* input;
  std::ifstream file;
  if (argc < 2) {
    input = &std::cin; // No file name provided, read from stdin
  } else {
    file.open(argv[1]);
    if (!file) {
      std::cerr << "Could not open the file.\n";
      return 1;
    }
    input = &file; // File opened successfully, read from file
  }
  std::string content(
      (std::istreambuf_iterator<char>(*input)),
      std::istreambuf_iterator<char>());
  SE_TARGET_STATE(parse_content(content));
  return 0;
}
