/*
 * codepage support (modified from julian@whistle.com)
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <syslog.h>

#include <netatalk/endian.h>

#include "globals.h"
#include "volume.h"
#include "codepage.h"

int codepage_read(struct vol *vol, const char *path)
{
  unsigned char buf[CODEPAGE_FILE_HEADER_SIZE];
  u_int16_t id;
  int fd, i;
  
  if ((fd = open(path, O_RDONLY)) < 0) {
    syslog(LOG_ERR, "%s: failed to open codepage", path);
    return -1;
  }
  
  /* Read the codepage file header. */
  if(read(fd, buf, sizeof(buf)) != sizeof(buf)) {
    syslog( LOG_ERR, "%s: failed to read codepage header", path);
    goto codepage_fail;
  }

  /* Check the file id */
  memcpy(&id, buf, sizeof(id));
  id = ntohs(id);
  if (id != CODEPAGE_FILE_ID) {
      syslog( LOG_ERR, "%s: not a codepage", path);
      goto codepage_fail;
  } 

  /* check the version number */
  if (*(buf + 2) != CODEPAGE_FILE_VERSION) {
      syslog( LOG_ERR, "%s: codepage version not supported", path);
      goto codepage_fail;
  } 

  /* skip to the start of the data */
  memcpy(&id, buf + 4, sizeof(id));
  id = ntohs(id);
  lseek(fd, id, SEEK_SET);

  /* here's the deal. we start with a default map that doesn't do
     anything. the code page provides pairs of mappings which can
     over-write none, some, or all of that default map. */
  if (!vol->v_utompage && 
      ((vol->v_utompage = (unsigned char *) malloc(128)) == NULL)) {
    syslog( LOG_ERR, "%s: Unable to allocate memory", path);
    goto codepage_fail;
  }

  if (!vol->v_mtoupage && 
      ((vol->v_mtoupage = (unsigned char *) malloc(128)) == NULL)) {
    syslog( LOG_ERR, "%s: unable to allocate memory", path);
    free(vol->v_utompage);
    vol->v_utompage = NULL;
    goto codepage_fail;
  }

  for (i = 0; i < 128; i++) {
    vol->v_utompage[i] = vol->v_mtoupage[i] = i + 0x80;
  }

  /* mtoupage is the the equivalent of samba's unix2dos. utompage is
   * the equivalent of dos2unix. it's a little confusing due to a
   * desire to match up with mtoupath and utompath. */
  while (read(fd, buf, 2) == 2) {
    /* don't allow mapping of 7-bit ascii characters */
    if (*buf < 0x80 || *(buf + 1) < 0x80) 
      continue;
    vol->v_mtoupage[*buf - 0x80] = *(buf + 1);
    vol->v_utompage[*(buf + 1) - 0x80] = *buf;
  }
  close(fd);
  return 0;

codepage_fail:
  close(fd);
  return -1;
}
