#if HAVE_CONFIG_H
# include "../config.h"
#endif

#include <assert.h>
#include <errno.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <nettle/base64.h>

#include "test-utils.h"

void __attribute__ ((noreturn))
die (const char *format, ...)
{
  va_list args;
  va_start (args, format);
  vfprintf (stderr, format, args);
  va_end (args);
  fprintf (stderr, "\n");
  abort ();
}

static void *
xalloc (size_t size)
{
  void *p = malloc (size);
  if (!p)
    die ("Memory exhausted.");

  return p;
}

void
hash_from_base64 (struct sigsum_hash *dst, const char *b64)
{
  struct base64_decode_ctx ctx;
  size_t length = strlen (b64);
  size_t dst_length;
  uint8_t buf[BASE64_DECODE_LENGTH(44)];

  if (length != 44)
    die ("unexpected base64 input length");

  base64_decode_init (&ctx);
  dst_length = sizeof(buf); /* Will be required for nettle-4. */
  if (!base64_decode_update (&ctx, &dst_length, buf, length, b64))
    die ("base64_decode_update failed");
  if (dst_length != sizeof (dst->h))
    die ("unexpected base64 size");
  if (!base64_decode_final (&ctx))
    die ("base64_decode_final failed");

  memcpy (dst->h, buf, sizeof (dst->h));
}

unsigned
path_from_base64 (unsigned max_size, struct sigsum_hash *path, const char *const *b64)
{
  unsigned i;
  for (i = 0; b64[i] != NULL; i++)
    {
      if (i >= max_size)
	abort ();
      hash_from_base64 (&path[i], b64[i]);
    }
  return i;
}

void
dump_hex (FILE *f, size_t size, const uint8_t *data)
{
  for (size_t i = 0; i < size; i++)
    {
      if (i && !(i % 8))
	fprintf (f, " ");
      fprintf (f, "%02x", data[i]);
    }
  fprintf(f, "\n");
}

size_t
read_src_file (const char *name, char **data)
{
  const char *srcdir = getenv("srcdir");
  FILE *f;
  long size;
  if (srcdir && srcdir[0])
    {
      char *buf;
      if (asprintf (&buf, "%s/%s", srcdir, name) < 0)
	return 0;

      f = fopen(buf, "rb");
      free(buf);
    }
  else
    f = fopen(name, "rb");

  if (!f)
    die ("failed to open file '%s': %s\n", name, strerror (errno));

  if (fseek (f, 0, SEEK_END) < 0)
    die ("fseek SEEK_END failed: %s\n", strerror (errno));

  size = ftell (f);
  if (size < 0)
    die ("ftell failed: %s\n", strerror (errno));

  if (fseek (f, 0, SEEK_SET) < 0)
    die ("fseek SEEK_SET failed: %s\n", strerror (errno));

  *data = xalloc (size + 1);

  if (fread (*data, 1, size + 1, f) != (size_t) size)
    die ("unexpected read size\n");

  if (ferror (f))
    die ("read failed");

  fclose (f);

  return size;
}
