Examinador de archivos

XM es un pequeño programa en C que hace un volcado de bytes por consola de cualquier archivo que se le pase por línea de comandos.

Muestra bloques sucesivos de 320 bytes en hexadecimal y en modo texto cuando es posible.

Permite desplazarse entre los bloques mediante las teclas de comando Arriba, Abajo, Inicio y Fin.

Se sale pulsando Escape.

Compilado con MinGW (Code::Blocks 13.12).

Descargar código fuente.

/*
    xm.c

    Hace un volcado de bytes por consola
    del archivo que se le pasa como parámetro
    en línea de comandos.
*/

#include <stdio.h>
#include <conio.h>
#include <ctype.h>
#include <windows.h>

#define COL 16
#define LIN 20

const int BLOQUE = LIN * COL;

typedef enum
{
  eSalir = 27,           /* Escape */
  ePrincipio = 71,       /* 'G' */
  eAnterior = 72,        /* 'H' */
  eFinal = 79,           /* 'O' */
  eSiguiente = 80,       /* 'P' */
  eMovimiento = 224
} eComando;

typedef struct
{
  unsigned long bytes;   /* Tamaño del archivo en bytes */
  unsigned int bloques;  /* Cantidad de bloques de 320 bytes */
  unsigned int resto;    /* Cantidad de bytes en el último bloque */
  unsigned int actual;   /* Número de orden del bloque actual */
} Parte;

void gotoxy(short x, short y)
{
  COORD pos;
  pos.X = x;
  pos.Y = y;
  SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}

void mostrarHexa(long pos, unsigned char *mem, unsigned int parte)
{
  printf("%8lX: ", pos);
  while(parte--)
  {
    printf(" %02X", *(mem++));
  }
}

void mostrarTexto(unsigned char *mem, unsigned int parte)
{
  while(parte--)
  {
      printf("%c", isprint(*mem)? *mem: '.');
    mem++;
  }
}

char leerComando()
{
  unsigned char c;

  gotoxy(0, 24);
  printf("<Arr> Anterior | <Aba> Siguiente | <Ini> Principio | <Fin> Final | <Esc> Salir");

  do
  {
    c = getch();
    if (c == eMovimiento) c = getch();
  } while(!(c == eAnterior ||
            c == eSiguiente ||
            c == ePrincipio ||
            c == eFinal ||
            c == eSalir));

  return c;
}

char mostrarBloque(FILE *arch, Parte *p, const char *nomArch)
{
  unsigned char mem[BLOQUE], *m;
  long pos = p->actual * BLOQUE;
  unsigned int parte = p->actual < p->bloques? BLOQUE: p->resto;
  unsigned int lin = parte / COL, resto;
  int y = 3;

  system("cls");
  printf("Archivo %s (%ld bytes)\nParte %d de %d",
    nomArch, p->bytes, p->actual + 1, p->bloques + !!p->resto);

  fseek(arch, pos, SEEK_SET);
  fread(mem, parte, 1, arch);

  gotoxy(0, y);
  m = mem;
  while(lin--)
  {
    mostrarHexa(pos, m, COL);
    gotoxy(80 - COL, y);
    mostrarTexto(m, COL);
    putchar('\n');

    m += COL; pos += COL;
    y++;
  }

  resto = parte % COL;
  if(resto)
  {
    mostrarHexa(pos, m, resto);
    gotoxy(80 - COL, y);
    mostrarTexto(m, resto);
  }

  return leerComando();
}

int main(int argc, char *argv[])
{
  FILE *arch;
  Parte par;
  unsigned char com;

  if(argc < 2)
  {
      puts("\nSintaxis: XM archivo\n\n");
      return 1;
  }

  if(!(arch = fopen(argv[1], "rb")))
  {
      printf("\nEl archivo %s no se encuentra\n\n", argv[1]);
      return 1;
  }

  fseek(arch, 0L, SEEK_END);

  par.bytes = ftell(arch);
  par.bloques = par.bytes / BLOQUE;
  par.resto = par.bytes % BLOQUE;
  par.actual = 0;

  com = mostrarBloque(arch, &par, argv[1]);
  while (com != eSalir)
  {
    switch(com)
    {
      case eSiguiente:
        if(par.actual < par.bloques) par.actual++;
        break;
      case eAnterior:
        if(par.actual) par.actual--;
        break;
      case eFinal:
        par.actual = par.bloques - !par.resto;
        break;
      case ePrincipio:
        par.actual = 0;
    }
    com = mostrarBloque(arch, &par, argv[1]);
  }

  fclose(arch);

  return 0;
}

Comentarios

Entradas populares de este blog

Fractales

Vida

Permutaciones, combinaciones, variaciones y particiones