#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <memory.h>
#include <fstream>
#include <vector>
#include "ASN1.h"
#include "../Base64/Base64.h"
#include "../Base64/Base64.cpp"


int main(int argc, char *argv[])
{
  if (argc != 2)
  {
    printf("Usage: %s key\n", argv[0]);
    return -1;
  }

  std::ifstream infile(argv[1]);
  if (!infile.is_open())
  {
    printf("Couldn't open file %s\n", argv[1]);
    return -1;
  }

  std::string line;
  std::string base64;
  while (std::getline(infile, line))
  {
    if ( line.size() < 5 || memcmp(line.c_str(), "-----", 5) != 0 )
      base64 += line;
  }

  std::vector<uint8_t> decoded;
  Base64::Decode(base64, decoded);

  std::vector< std::vector<uint8_t> > publicKeyValues;

  printf("\ndecoding:\n");
  uint8_t* buf = (uint8_t*)decoded.data();
  for (int i = 0; i < decoded.size(); i++)
  {
    const char* typeNames[] = { "INVALID", "SEQUENCE", "INTEGER", "OBJECT", "NULL", "BIT STRING" }; 
    int typ = 0;
    if (buf[i] == 0x30) typ = 1; // seq
    if (buf[i] == 0x02) typ = 2; // int
    if (buf[i] == 0x03) typ = 5; // bits
    if (buf[i] == 0x05) typ = 4; // null
    if (buf[i] == 0x06) typ = 3; // obj

    unsigned offset = i;
    i++;
    unsigned d = 0;
    unsigned hl = (buf[i] == 0x82) ? 4 : 2;
    if (hl == 4)
      i++;
    unsigned len = buf[i];
    i++;
    if (hl == 4)
    {
      len <<= 8;
      len |= buf[i];
      i++;
    }

    if (typ != 0)
        printf("% 5i:d=%i  hl=%i l=% 4i cons: %s\n", offset, d, hl, len, typeNames[typ]);

    std::vector<uint8_t> publicKeyValue;
    if (typ == 2)
    {
      while (len--)
      {
        publicKeyValue.push_back(buf[i]);
        i++;
      }
      publicKeyValues.push_back(publicKeyValue);
    }

    if (typ == 3)
      while (len--)
        i++;

    if (typ == 5)
      i++;

    i--;
  }

  for (int i = 0; i < publicKeyValues.size(); i++)
  {
    std::vector<uint8_t>& v = publicKeyValues[i];
    printf("val: ");
    for (int i = 0; i < v.size(); i++)
      printf("%02X", v[i]);
    printf("\n");
  }

  infile.close();

  ASN1Object asn1object(decoded);
  asn1object.Print(2);

}


