#include <stdint.h> /* Funktionsbibliothek: Integer */
#include <stdlib.h> /* Funktionsbibliothek: Hilfsfunktionen */
#include <stdio.h>  /* Funktionsbibliothek: Standard Ein- Ausgabe */

#include "main.h"
#include "decrypt.h"

// disable deprecated warning
#pragma warning(disable : 4996)

void decipher(uint32_t num_cycles, uint32_t v[2], uint32_t const k[4])
{
  unsigned int i;
  const uint32_t delta = 0x9E3779B9;                       // decipher changes:
  uint32_t v0 = v[0], v1 = v[1], sum = delta * num_cycles; // sum = delta * num_cycles;
  for (i = 0; i < num_cycles; i++)
  {
    v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[(sum >> 11) & 3]); //-=
    sum -= delta;                                                      //-=, exchange lines above and below
    v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[sum & 3]);         //-=
  }
  v[0] = v0;
  v[1] = v1;
}

int decrypt(char *LoadFName, char *SaveFName, uint32_t key[4])
{
  int ErrorCode = NO_ERROR; /* Error-Code-Variable */
  FILE *LoadFile;           /* File welches geladen wird */
  FILE *SaveFile;           /* File welches gespeichert wird */
  char block[2] = {0};
  uint32_t block_uint32[2] = {0};
  uint32_t num_cycles = 16;

  /* Kontrolliertes oeffnen der Files */
  if ((LoadFile = fopen(LoadFName, "rb")) == NULL)
    ErrorCode = ERROR_OPEN_LOAD_FILE;
  if ((SaveFile = fopen(SaveFName, "wb")) == NULL)
    ErrorCode = ERROR_OPEN_SAVE_FILE;

  /* Alle Filezugriffe moeglich ? */
  if (ErrorCode == NO_ERROR)
  {
    do
    {
      // reset vars
      block_uint32[0] = 0;
      block_uint32[1] = 0;

      // get 2 blocks from file
      int x = 0;
      while (x < 2)
      {
        fscanf(LoadFile, "%u ", &block_uint32[x]);
        x++;
      }

      decipher(num_cycles, block_uint32, key);

      // store decrypted block to file
      fputc((char)block_uint32[0], SaveFile);
      fputc((char)block_uint32[1], SaveFile);

    } while (!feof(LoadFile));
  }

  /* Wenn Orignalfile geoffnet werden konnte */
  if (ErrorCode != ERROR_OPEN_LOAD_FILE)
    fclose(LoadFile);
  /* Wenn Ausgabefile geschrieben werden konnte  */
  if (ErrorCode != ERROR_OPEN_SAVE_FILE)
    fclose(SaveFile);

  return (ErrorCode); /* Rueckgabe des Fehlercodes */
}
