#include <stdio.h>
#include <stdlib.h>

typedef struct
{
  unsigned signature;
  unsigned part_pag;
  unsigned file_size;
  unsigned rel_item;
  unsigned hdr_size;
  unsigned min_mem;
  unsigned max_mem;
  unsigned ss_reg;
  unsigned sp_reg;
  unsigned chk_summ;
  unsigned ip_reg;
  unsigned cs_reg;
  unsigned relt_off;
  unsigned overlay;
} EXE_HDR;

typedef struct 
{
  unsigned offset;
  unsigned segment;
} RELOC_TAB;

void main(int, char *[]);
int get_exeh(EXE_HDR *exeh, RELOC_TAB **rtb,
	     FILE *exe_file);
int listhdr(char *path);

void main(int argc, char *argv[])
{
  printf("Просмотр заголовка exe-файла\n"
    "(C) Фролов А.В., 1995\n\n");

  if(argc != 2)
  {
    printf("  Укажите путь к exe-файлу в качестве"
		      "параметра\n" );
    return;
  }

  if(listhdr(argv[1]) != 0)
  {
    printf("Ошибка в формате файла или нет такого"
      "файла\n");
    return;
  }
}

// -------------------------------------------
// listhdr
// Отображение заголовка exe-файла
// -------------------------------------------

int listhdr(char *path)
{
  EXE_HDR     header;
  RELOC_TAB   *reloc;
  FILE        *inpfile;
  int         i;

  if((inpfile = fopen(path,"rb")) == 0)
    return(-1);

  if(get_exeh(&header,&reloc,inpfile) != 0)
  {
    fclose(inpfile);
    return(-1);
  }
  printf("Магическое число:                   %04X\n"
	 "Длина последней страницы файла:      %d\n"
	 "Количество страниц в файле:          %d\n"
	 "Кол. элементов табл. перемещений:    %d\n"
	 "Размер заголовка в параграфах:       %d\n"
	 "Минимальная память для программы:    %04X\n"
	 "Максимальная память для программы:   %04X\n"
	 "Значение адреса стека SS:SP:         %04X:%04X\n"
	 "Контрольная сумма:                   %04X\n"
	 "Значения для регистров CS:IP:        %04X:%04X\n"
	 "Смещение табл. перемещений:          %02X\n"
	 "Номер оверлея:                       %d\n",
	 header.signature, header.part_pag,
	 header.file_size, header.rel_item,
	 header.hdr_size,  header.min_mem,
	 header.max_mem,   header.ss_reg,
	 header.sp_reg,    header.chk_summ,
	 header.cs_reg,    header.ip_reg,
	 header.relt_off,  header.overlay);

  if(reloc != 0)
  {
    printf("\nСодержимое таблицы перемещений:\n\n");

      for(i=0; i < header.rel_item; i++)
      {
	printf("%04X:%04X\n",
	  (reloc+i)->segment, (reloc+i)->offset);
      }

      free(reloc);
   }

   fclose(inpfile);
   return(0);
}

// -------------------------------------------
// get_exeh
// Прочитать заголовок exe-файла
//
// Функция читает заголовок exe-файла в структуру
// типа exe_HDR, заказывает память для таблицы
// размещений сегментов и считывает таблицу
// в эту область. Адрес заказанной области
// помещается по адресу, указанному через
// параметр rtb.
// Если таблица размещений отсутствует, память для
// нее не заказывается.
//
// Параметры:
//   exeh -  указатель на структуру, которая
//           должна быть заполнена информацией
//           из заголовка exe-файла
//
//   rtb  -  указатель на слово памяти, в котором
//           хранится указатель на таблицу
//           размещений сегментов программы
//
//   exe_file - указатель на открытый exe-файл
//
// Возвращаемое значение:
//   0 при успешном считывании заголовка;
//  -1 в случае неправильного формата заголовка
// -------------------------------------------

int get_exeh(EXE_HDR *exeh, RELOC_TAB **rtb,
	     FILE *exe_file)
{
  int i, j, k;

  // Считываем форматированную часть заголовка
  for(i=0; i < sizeof(EXE_HDR); i++)
  {
    *(((char*)exeh) + i) = fgetc(exe_file);
    if(feof(exe_file)) break;
  }

  // Убеждаемся, что это EXE-файл
  if(exeh->signature != 0x5a4d) return(-1);

  // Eсли есть таблица перемещений,
  // заказываем для нее память
  if((i = exeh->rel_item) != 0)
  {
    *rtb =
      (RELOC_TAB*)malloc(i * sizeof(RELOC_TAB) + 16);

    // Считываем таблицу перемещений
    for(k=0; k<i; k++)
    {
      for(j=0; j < sizeof(RELOC_TAB); j++)
      {
	*((char*)(*rtb)+j+k*sizeof(RELOC_TAB)) =
	   fgetc(exe_file);
	if(feof(exe_file)) break;
      }
    }
  }
  else
    *rtb = (RELOC_TAB *)NULL;
  return(0);
}

