/*
* hacha.c: Une archivos con el Hacha de Windows en Linux.
* Copyright (c) BatchDrake 2006 <BatchDrake@gmail.com>
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
inline char *xstrdup (char *str)
{
register char *r;
if ((r = strdup (str)) == NULL)
abort ();
return r;
}
inline void *xmalloc (int size)
{
register void *r;
if ((r = malloc (size)) == NULL)
abort ();
return r;
}
static int __expect_hacha_boundary (FILE *fp)
{
char buf [5];
if (fread (buf, 5, 1, fp) < 1)
return -1;
if (memcmp (buf, "?????", 5) == 0)
return 1;
return 0;
}
void expect_hacha_marker (char *file, FILE *fp)
{
int i;
if ((i = __expect_hacha_boundary (fp)) == -1)
{
fprintf (stderr, "%s: Final de fichero inesperado. Archivo incompleto.\n", file);
exit (1);
}
else if (i == 0)
{
fprintf (stderr, "%s: Separador interno no encontrado (¿formato no reconocido?). Se aborta.\n", file);
exit (1);
}
}
int string_end (FILE *fp)
{
int r;
r = __expect_hacha_boundary (fp);
fseek (fp, -5, SEEK_CUR);
return r;
}
char *get_hacha_string (FILE *fp)
{
char buffer [256];
char *result;
int i;
for (i = 0; i < 256 && !string_end (fp); i++)
fread (&buffer[i], 1, 1, fp);
buffer[i] = '\0';
return xstrdup (buffer);
}
int main (int argc, char **argv)
{
FILE *fp;
FILE *out;
FILE *this_input;
char b;
char *out_file, *tmp;
char *in_files, *template;
char buffer [4096];
int size;
int frag_size;
int chunk_size;
int version;
register int frsize;
register int i, p;
register int total_amount;
if (argc != 2)
{
fprintf (stderr, "Forma de uso: %s archivo.0\n", argv[0]);
return 0;
}
fp = fopen (argv[1], "rb");
if (fp == NULL)
{
perror (argv[1]);
exit (2);
}
expect_hacha_marker (argv[1], fp);
fread (&version, sizeof (int), 1, fp);
printf ("\tHacha version 0.%d\n", version
);
expect_hacha_marker (argv[1], fp);
out_file = get_hacha_string (fp);
expect_hacha_marker (argv[1], fp);
printf ("\tArchivo de salida: %s\n", out_file
);
tmp = get_hacha_string (fp);
if (!sscanf (tmp, "%i", &size))
{
fprintf (stderr, "%s: Error en formato de tamaño total.\n", argv[1]);
exit (3);
}
free (tmp);
expect_hacha_marker (argv[1], fp);
tmp = get_hacha_string (fp);
if (!sscanf (tmp, "%i", &frag_size))
{
fprintf (stderr, "%s: Error en formato de tamaño total.\n", argv[1]);
exit (3);
}
free (tmp);
expect_hacha_marker (argv[1], fp);
printf ("\tTamaño total: %g MiB\n", (float) size
/ (1024.0
* 1024.0
));
printf ("\tTamaño por fragmento: %g MiB\n", (float) frag_size
/ (1024.0
* 1024.0
));
printf ("\nSe espera que el archivo se haya dividido en %d partes.\n\n", size
/ frag_size
+ ((size
% frag_size
) ? 1
: 0
));
frsize = frag_size;
out = fopen (out_file, "wb");
if (out == NULL)
{
perror (out_file);
exit (4);
}
template = xstrdup (argv[1]);
in_files = xmalloc (strlen (argv[1]) + 5);
strcpy (in_files, argv[1]);
template [strlen (template) - 1] = '\0';
for (i = 0, total_amount = 0; total_amount < size; i++)
{
printf ("Ligando fichero nº %d... ", i
+ 1
);
fflush (stdout);
if (i)
{
sprintf (in_files, "%s%d", template, i);
this_input = fopen (in_files, "rb");
if (this_input == NULL)
{
perror (in_files);
fprintf (stderr, "El archivo es necesario para la recomposición pero no se ha podido abrir. Se aborta.\n");
unlink (out_file);
exit (1);
}
}
else
this_input = fp;
if (total_amount + frsize > size)
frsize = size - total_amount;
for (p = 0; p < frsize; )
{
chunk_size = ((p + 4096) <= frsize) ? 4096 : frsize - p;
if ((p % 4096) == 0 || chunk_size < 4096)
fprintf (stderr, "%3d%%\033[4D", ((p + chunk_size)) / (frsize / 100));
if (fread (buffer, chunk_size, 1, this_input) < 1)
{
fprintf (stderr, "%s: fatal: El fichero está incompleto (¿descarga interrumpida?). Se aborta.\n", in_files);
unlink (out_file);
exit (1);
}
if (fwrite (buffer, chunk_size, 1, out) < 1)
{
perror (out_file);
fprintf (stderr, "%s: fatal: Ha ocurrido un problema al escribir el fichero resultante. Se aborta.\n", in_files);
unlink (out_file);
}
p += chunk_size;
}
total_amount += p;
}
return 0;
}