/* Le fichier lit_map.c contient les routines de lecture écriture de
 * la table de clavier
 */

#include "edimap.h"
#include "func.h"

#define HUNK_HEADER	0x3f3
#define HUNK_CODE	0x3e9
#define HUNK_RELOC32	0x3ec
#define HUNK_END	0x3f2

#define TAILLE0_OFF 0x14
#define CODE_OFF 0x18
#define TAILLE1_OFF 0x1c
#define FIX_OFF 0x20
#define AdNOM_OFF 0x0c
#define AdTABLE_OFF 0x0eL
#define LKM 0x12
#define STR_OFF 0x2a4

/*----------------------------------------------------*/
/* on a dans un buffer filebuf le fichier table de clavier qui a été chargé
 * et qui a pour longueur taille
 */
lit_table()
{
    ULONG *plong, code_size, pKeybase, longtab, nb_str, *deb_p_str;
    UWORD *pword;

	plong = (ULONG *)filebuf;
	if (*plong++ != HUNK_HEADER) return ERROR;
	if (*plong++ != 0L) return ERROR;
	if (*plong++ != 1L) return ERROR;
	
 	plong = (ULONG *)(filebuf+CODE_OFF);
	if (*plong++ != HUNK_CODE) return ERROR;
	code_size = *plong++; /* taille du hunk en LONG */      
	pbase = (UBYTE *)(plong);
	pword = (UWORD *)(pbase + AdNOM_OFF);
/*printf("pnom %lx",*pword);*/
	pnom =  (UBYTE *)(pbase + *(pword++)); ++pword;

/*printf("pword %lx,ad lkmt %x\n",pword,*pword);*/
	keymap.km_LoKeyMapTypes = (UBYTE *)(pbase + *pword++); ++pword;
	keymap.km_LoKeyMap = (ULONG *)(pbase + *pword++); ++pword;
	keymap.km_LoCapsable = (UBYTE *)(pbase + *pword++); ++pword;
	keymap.km_LoRepeatable = (UBYTE *)(pbase + *pword++); ++pword;
	keymap.km_HiKeyMapTypes = (UBYTE *)(pbase + *pword++); ++pword;
	keymap.km_HiKeyMap = (ULONG *)(pbase + *pword++); ++pword;
	keymap.km_HiCapsable = (UBYTE *)(pbase + *pword++); ++pword;
	keymap.km_HiRepeatable = (UBYTE *)(pbase + *pword);

/*printf("pbase= %lx\n",pbase);*/

	longtab = code_size * 4;

	plong += code_size;

	if (*plong++ != HUNK_RELOC32) return ERROR;
/*	pnb_str = (ULONG *)(pbase + longtab + 4);*/
	nb_str = *plong++;
	if (*plong++ != 0L) return ERROR;
	deb_p_str = plong;
/*printf("longtab %lx, nb_str %lx\n",longtab, nb_str);*/
/*printf("pnb_str %lx,deb_p_str %lx\n",pnb_str,deb_p_str);*/
	pKeybase = (UBYTE *)(keymap.km_LoKeyMap) - pbase;
	init_p(deb_p_str,nb_str,pKeybase,buffer);

	return BON;
}
/*--------------------------------*/
/* initialise la table des strings */

void init_p(p,nb,keybase,t)
ULONG	*p,		/* debut de la table d'adresses a reloger */
	nb,		/* nb d'adresses a reloger */
	keybase;	/* position dans le fichier du debut des keys */
struct P_String *t;	/* buffer des strings de taille P_SIZE (128) */
{
  int key, i;

    for(i=0; i<(nb-9); i++)
    {   key = (*p - keybase)/4; /* numero de la touche concernee */
	t[key].p = (UBYTE *)(*(APTR)(pbase + *p++)) ; /*off de l'adr du str */
	buf_p[key].p = (ULONG)t[key].p + pbase; /* adr du str */
	t[key].l = (UBYTE)key;	/* numero de la touche */
    }
    t = tri(t,P_SIZE);	/* on tri par numero */
    for (key = 1; t[key].l; key++)
    {  buf_p[t[key-1].l].l = t[key].p - t[key-1].p;
    }
    buf_p[t[key-1].l].l = (UBYTE *)(pnom - pbase) - t[key-1].p;
}
/*--------------------------------*/
/* tri des adresses de strings */

struct P_String *tri(t,nb)
struct P_String *t;
int nb;
{
  struct P_String pr;
  int i, ip, j, ik, l;

    ip = --nb;		/* décremente pour garder 0 a la fin */
    while (ip >= 2)
    {   ip /= 2; j = 0;
        ik = nb - ip;
	while (j < ik)
	{  i = j;
	   while (i >= 0)
	   {   l = i + ip;
	       if (t[i].p <= t[l].p) break;
	       pr = t[i]; t[i] = t[l]; t[l] = pr;
	       i -= ip;
	   }
	   j++;
	}
    } 
    while (!(t->p)) t++;  
    return(t);
}
/*--------------------------------------------*/
/* Création sur disque de la nouvelle table */

ecr_table(new_nom,new_table)
char *new_nom, *new_table;
{
  struct FileHandle *fout;
  ULONG *t_reloc;
  ULONG l_nom, l, wpnom;
  int i, l_reloc;
  UBYTE *p_byte, *pbase;

    if ((fout = Open(new_nom,MODE_NEWFILE)) == NULL)
    {  printf("Je ne peux ouvrir le fichier %s\n",new_nom); 
       return ERROR;
    }

    pbase = filebuf + FIX_OFF;
    Write(fout,filebuf,78L); /* ecrit le meme debut que l'on modifiera */

/* le bloc qui suit est inutile car le même en fait */
/*    mise_a_jour = 46L;
    Seek(fout,mise_a_jour,OFFSET_BEGINNING)
    p_byte = keymap.km_LoKeyMapTypes - pbase;
    Write(fout,p_byte,4L);
    p_byte = keymap.km_LoKeyMap - pbase;
    Write(fout,p_byte,4L);
    p_byte = keymap.km_LoCapsable - pbase;
    Write(fout,p_byte,4L);
    p_byte = keymap.km_LoRepeatable - pbase;
    Write(fout,p_byte,4L);
    p_byte = keymap.km_HiKeyMapTypes - pbase;
    Write(fout,p_byte,4L);
    p_byte = keymap.km_HiKeyMap - pbase;
    Write(fout,p_byte,4L);
    p_byte = keymap.km_HiCapsable - pbase;
    Write(fout,p_byte,4L);
    p_byte = keymap.km_HiRepeatable - pbase;
 */
    t_reloc = (ULONG *)buffer; /* reutilise buffer */   
    l_reloc = ajust_table(t_reloc);
    Write(fout,keymap.km_LoCapsable,8L);
    Write(fout,keymap.km_HiCapsable,7L);
    Write(fout,keymap.km_LoRepeatable,8L);
    Write(fout,keymap.km_HiRepeatable,7L);
    Write(fout,keymap.km_LoKeyMapTypes,64L);
    Write(fout,keymap.km_HiKeyMapTypes,56L);
    Write(fout,keymap.km_LoKeyMap,256L);
    Write(fout,keymap.km_HiKeyMap,224L);

    for (i=0; i<P_SIZE; i++)
    { if (buf_p[i].p) Write(fout,buf_p[i].p,(LONG)buf_p[i].l);
    }

    l_nom = strlen(new_table);
    Write(fout,new_table,l_nom+1);
    
    l = Seek(fout,0L,OFFSET_CURRENT); /* où est-on */
    wpnom = (l + 3 - FIX_OFF)/4;
    l = 4 - l%4;
    l_nom = 0L;
    if (l != 4) Write(fout,&l_nom,l); /* padding en long */

    Write(fout,t_reloc,l_reloc*4);

    l = HUNK_END;
    Write(fout,&l,4L);

    Seek(fout,TAILLE0_OFF,OFFSET_BEGINING);
    Write(fout,&wpnom,4L);
    Seek(fout,TAILLE1_OFF,OFFSET_BEGINING);
    if (Write(fout,&wpnom,4L) != 4)
    { printf("pas de place sur le disque, fichier incomplet\n");
      return ERROR;
    }
    Close(fout);
    return BON;

}
/*--------------------------------------------*/
/* on crée la table de relocation finale */

ajust_table(t_reloc)
ULONG *t_reloc;
{
    ULONG off_str = STR_OFF;
    ULONG *p_Map;
    LONG j=0;
    int i;

	t_reloc[j++] = HUNK_RELOC32;
	j++;
	t_reloc[j++] = 0x00;
	p_Map = (ULONG *)keymap.km_LoKeyMap;
	for (i=0; i<P_SIZE; i++)
	{ if (buf_p[i].p)
	  { p_Map[i] = off_str;
	    off_str += buf_p[i].l;
	    t_reloc[j++] = 4*i + 0xc4;
	  }
	}

	t_reloc[j++] = 0x2a;
	t_reloc[j++] = 0x26;
	t_reloc[j++] = 0x22;
	t_reloc[j++] = 0x1e;
	t_reloc[j++] = 0x1a;
	t_reloc[j++] = 0x16;
	t_reloc[j++] = 0x12;
	t_reloc[j++] = 0x0e;
	t_reloc[j++] = 0x0a;
	t_reloc[j] = 0x00;
	
	t_reloc[1] = j-3;
	return (j+1);
}
