
#include <fcntl.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stddef.h>

#include "bogl.h"
#include "boglP.h"
#include "bogl-font.h"
#include "bogl-bgf.h"

struct bogl_bgf {
  void *f;    /* mmap area */
  off_t size; /* size of mmap area */
  struct bogl_font font; /* font descriptor */
};
#define bgf_of(font) \
  ((struct bogl_bgf *)((char *)(font) - offsetof(struct bogl_bgf, font)))

struct bogl_font *bogl_mmap_font(char *file)
{
  struct bogl_bgf *bgf = NULL;
  struct bogl_font *font = NULL;
  int fd = -1;
  struct stat buf;
  void *f = MAP_FAILED;

  bgf = (struct bogl_bgf *)malloc(sizeof(struct bogl_bgf));
  if (!bgf)
    goto fail;
  font = &bgf->font;

  fd = open(file, O_RDONLY);
  if (fd == -1)
    goto fail;

  if (bogl_cloexec(fd) < 0)
    goto fail;

  if (fstat(fd, &buf))
    goto fail;
  bgf->size = buf.st_size;

  if (buf.st_size < 4)
    goto fail;

  f = mmap(0, buf.st_size, PROT_READ, MAP_SHARED, fd, 0);
  if (f == MAP_FAILED)
    goto fail;
  bgf->f = f;

  if (memcmp("BGF1", f, 4))
    goto fail;

  memcpy(font, f + 4, sizeof(*font));
  font->name = ((void *)font->name - (void *)0) + f;
  font->offset = ((void *)font->offset - (void *)0) + f;
  font->index = ((void *)font->index - (void *)0) + f;
  font->content = ((void *)font->content - (void *)0) + f;

done:
  if (fd != -1)
    close(fd);
  return font;

fail:
  if (bgf) {
    free(bgf);
    bgf = NULL;
    font = NULL;
  }
  if (f != MAP_FAILED)
    munmap(f, buf.st_size);
  goto done;
}

void bogl_munmap_font(struct bogl_font *font)
{
  struct bogl_bgf *bgf = bgf_of(font);
  munmap(bgf->f, bgf->size);
  free(bgf);
}
