//
// Read PoC(generated by intCoding fuzzer(../fuzezer) and reproduce the issue
//
#include <cstdint>
#include <cstring>
#include <memory>
#include <vector>
#include <iostream>
#include <fstream>

#include "integerCoding.h"

void decompressInt(uint8_t const *data, size_t size)
{
  if (size <= 8 + 4) {
    std::cout << "Size too small\n";
    return;
  }

  // Header 4 byes
  uint32_t n; // nInts
  memcpy(&n, data, 4);

  using Compressor = tinyusdz::Usd_IntegerCompression;
  size_t compBufferSize = Compressor::GetCompressedBufferSize(n);

  // 8bytes: compressed size.
  uint64_t compSize;
  memcpy(&compSize, data + 4, 8);

  if (compSize < 4) {
    std::cout << "Compression size too  small.\n";
    return;
  }

  if ((compSize + 8 + 4) > size) {
    std::cout << "Compression size exceeds input data size.\n";
    return;
  }

  if (compSize > compBufferSize) {
    std::cout << "Compression size exceeds input data size.\n";
    return;
  }

  std::cout << "n = " << n << "\n";
  std::cout << "compSize = " << compSize << "\n";
  std::cout << "compBufferSize = " << compBufferSize << "\n";

  std::vector<char> compBuffer;
  compBuffer.resize(compBufferSize);

  memcpy(compBuffer.data(), data + 8 + 4, compSize);

  std::vector<uint32_t> output(n);

  std::string err;
  bool ret = Compressor::DecompressFromBuffer(compBuffer.data(), compSize, output.data(), n, &err);

  if (err.size()) {
    std::cout << err << "\n";
  }

  if (ret) {
    std::cout << "OK\n";
  } else {
    std::cout << "Failed(but failure expected)\n";
  }
}

int main(int argc, char **argv)
{
  if (argc < 2) {
    std::cout << "Needs input.poc\n";
    return -1;
  }

  std::vector<uint8_t> buf;

  std::ifstream ifs(argv[1], std::ios::binary | std::ios::in);
  ifs.seekg(0, ifs.end);
  size_t sz = static_cast<size_t>(ifs.tellg());
  ifs.seekg(0, ifs.beg);

  buf.resize(sz);
  ifs.read(reinterpret_cast<char *>(buf.data()), static_cast<std::streamsize>(sz));

  decompressInt(buf.data(), buf.size());
}
