27 Rutinas de ficheros y compresión

Las siguientes rutinas implementan un sistema de ficheros I/O con buffer rápido, que soporta la lectura y escritura de ficheros comprimidos usando un algoritmo de buffer de anillo basado en el compresor LZSS de Haruhiko Okumura. Esto no consigue tan buenas compresiones como zip o lha, pero la descompresión es muy rápida y no requiere mucha memoria. Los ficheros comprimidos siempre comienzan con el valor de 32 bits F_PACK_MAGIC, y autodetecta ficheros con el valor F_NOPACK_MAGIC.

Los siguients bit FA_* están garantizados en todas las plataformas: FA_RDONLY, FA_HIDDEN, FA_SYSTEM, FA_LABEL, FA_DIREC y FA_ARCH. No use otros bits de DOS/Windows, o su código no compilará en otras plataformas. Los bits FA_SYSTEM, FA_LABEL y FA_ARCH sólo son útiles bajo DOS/Windows (entradas con el bit de sistema, archivo y etiquetas de volúmen). FA_RDONLY es para directorios con el bit de sólo lectura en sistemas tipo DOS, o directorios sin permiso de escritura por el usuario actual en sistemas tipo Unix. FA_HIDDEN es para ficheros ocultos en DOS, o aquellos que compeinzan con '.' en sistemas Unix (excepto los ficheros '.' y '..'). FA_DIREC representa directorios. Los bits se pueden combinar usando '|' (operador OR binario).

Cuando estos bits son pasados a las funciones como el parámetro 'attrib', representan un superconjunto de los bits que debe tener un fichero para ser incluído en la búsqueda. Esto es, para que un fichero encaje con el patrón, sus atributos pueden contener cualquiera de los bits especificados, pero no debe contener ningúno de los bits no especificados. Por lo tanto, si usa 'FA_DIREC | FA_RDONLY', los ficheros y directorios normales serán incluídos junto con los ficheros y directorios de sólo lectura, pero no los ficheros y directorios ocultos. Similarmente, si usa 'FA_ARCH' entonces tanto los ficheros archivados como no archivados serán incluídos.


void get_executable_name(char *buf, int size);
Llena buf con la ruta completa del ejecutable actual, escribiendo como mucho size bytes. Esto normalmente viene de argv[0], pero en los sistemas Unix donde argv[0] no especifica la ruta, se buscará el fichero en $PATH.


char *fix_filename_case(char *path);
Convierte un nombre de fichero a un estado estandarizado. En platadormas DOS, los nombres serán todo mayúsculas. Devuelve una copia del parámetro de camino.

Relacionado con: fix_filename_slashes, fix_filename_path.
char *fix_filename_slashes(char *path);
Convierte los separadores de directorios de un nombre de fichero a un carácter estándar. En plataformas DOS, esto es la antibarra. Devuelve una copia del parámetro de camino.
Relacionado con: fix_filename_case, fix_filename_path.
char *fix_filename_path(char *dest, const char *path, int size);
Convierte un nombre de fichero parcial en una ruta completa, escribiendo en dest como máximo el número de bytes especificados. Devuelve una copia del parámetro dest.
Relacionado con: fix_filename_case, fix_filename_slashes.
char *replace_filename(char *dest, const char *path, const char *filename, int size);
Sustituye el camino+nombre de fichero especificados con un nuevo nombre de fichero, escribiendo en dest como máximo el número de bytes especificados. Devuelve una copia del parámetro dest.
Relacionado con: get_filename, replace_extension, append_filename.
char *replace_extension(char *dest, const char *filename, const char *ext, int size);
Sustituye el nombre de fichero+extensión especificados con una nueva extensión, escribiendo en dest como máximo el número de bytes especificados. Devuelve una copia del parámetro dest.
Relacionado con: get_extension, replace_filename.
char *append_filename(char *dest, const char *path, const char *filename, int size);
Concatena el nombre de fichero especificado al final del camino especificado, escribiendo en dest como máximo el número de bytes especificados. Devuelve una copia del parámetro dest.
Relacionado con: replace_filename.
char *get_filename(const char *path);
Cuando se le pasa el path específico de un fichero, devuelve un puntero a la porción del nombre del fichero. Tanto '\' como '/' son reconocidos como separadores de directorios.
Relacionado con: get_extension, put_backslash, replace_filename.
char *get_extension(const char *filename);
Cuando se le pasa un nombre de fichero completo (con o sin información de path) devuelve un puntero a la extensión del fichero.
Relacionado con: get_filename, put_backslash, replace_extension.
void put_backslash(char *filename);
Si el último caracter de un nombre no es '\', '/', '#' o un separador de dispositivo (ej: ':' bajo DOS), esta rutina concatenará un '\' o '/' (dependiendo de la plataforma). Nota: ignore el nombre de la función, está anticuado.
Relacionado con: get_extension, get_filename.
int file_exists(const char *filename, int attrib, int *aret);
Chequea la existencia de un fichero de nombre y atributos dados (lea más arriba), devolviendo distinto de cero si el fichero existe. Si aret no es NULL, contendrá los atributos del fichero existente al acabar la llamada. Si ocurre un error, el código de error de sistema será almacenado en errno.
Relacionado con: exists, file_size, file_time.
int exists(const char *filename);
Versión reducida de file_exists(), que comprueba la existencia de ficheros normales, los cuales pueden tener los bits de archivo o sólo lectura activados, pero no son ocultos, directorios, ficheros de sistema, etc.
Relacionado con: file_exists, file_size, file_time.
long file_size(const char *filename);
Devuelve el tamaño del fichero en bytes. Si el fichero no existe u ocurre un error, devolverá cero y almacenará el código de error de sistema en errno.
Relacionado con: file_exists, file_time.
time_t file_time(const char *filename);
Devuelve el tiempo de modificación de un fichero (número de segundos desde las 00:00:00 GMT del 1 de Enero de 1970).
Relacionado con: file_exists, file_size.
int delete_file(const char *filename);
Borra un fichero.


int for_each_file(const char *name, int attrib, void (*callback)(const char *filename, int attrib, int param), int param);
Encuentra todos los ficheros que se ajusten a la máscara (ej: *.exe) y atributos especificados (lea más arriba), y ejecuta callback() por cada uno de ellos. A callback() se le pasan tres parámetros, el primero es la cadena que contiene el nombre completo del fichero, el segundo los atributos del fichero, y el tercer parámetro es un entero que es copia de param (puede usar esto para lo que quiera). Si ocurre un error, el código de error será almacenado en errno, y callback() puede abortar for_each_file al activar errno. Devuelve el número de llamadas con éxito hechas a callback().


int al_findfirst(const char *pattern, struct al_ffblk *info, int attrib);
Función de bajo nivel para buscar ficheros. Esta función busca el primer fichero que concuerde con el patrón y los atributos de fichero especificados (lea más arriba). La información sobre el fichero (si existe) será puesta en la estructura al_ffblk que debe proveer usted. La función devuelve cero si se encontró un fichero, distinto de cero si no se encontró ninguno, y en este caso ajusta errno apropiadamente. La estructura al_ffblk tiene la siguiente forma:

     struct al_ffblk
     {
         int attrib;       - atributos del fichero encontrado
         time_t time;      - tiempo de modificación del fichero
         long size;        - tamaño del fichero
         char name[512];   - nombre del fichero
     };
Hay más cosas en esta estructura, pero son para uso interno.
Relacionado con: al_findnext, al_findclose.
int al_findnext(struct al_ffblk *info);
Esto encuentra el siguiente fichero en una búsqueda comenzada por al_findfirst. Devuelve cero si se encontró un fichero, distinto de cero si no se encontró ninguno, y en éste caso ajusta errno apropiadamente.
Relacionado con: al_findfirst, al_findclose.
void al_findclose(struct al_ffblk *info);
Esto cierra una búsqueda previamente abierta mediante al_findfirst().
Relacionado con: al_findfirst, al_findnext.
int find_allegro_resource(char *dest, const char *resource, const char *ext, const char *datafile, const char *objectname, const char *envvar, const char *subdir, int size);
Busca un archivo de recursos, ej allegro.cfg o language.dat. Pasándole una cadena resource describiendo qué se está buscando, junto con una información extra opcional como la extensión por defecto, en qué datafile mirar, qué nombre de objeto debería tener en el datafile, cualquier variable de entorno que se tenga que chequear, y cualquier subdirectorio que le gustaría comprobar, así como la localización por defecto, esta función mira en un infierno de sitios distintos :-) Devuelve cero si ha tenido éxito, y guarda el path absoluto del fichero (como mucho size bytes) en el parámetro dest.


void packfile_password(const char *password);
Activa el password de encriptación que será usado para todas las operaciones de lectura/escritura con ficheros abiertos en el futuro con las funciones packfile de Allegro (estén comprimidos o nó), incluyendo las rutinas de configuración, salvado y cargado. Los ficheros escritos con un password no pueden ser leídos a no ser que se seleccione el password correcto, por lo que cuidado: si olvida la clave, ¡nadie podrá recuperar su datos! Pase NULL o una cadena vacía para volver al modo normal, no encriptado. Si está usando esta función para evitar que otros accedan a sus ficheros de datos, tenga cuidado de no salvar una copia obvia de su clave en el ejecutable: si hay cadenas como "Soy la clave del fichero de datos", sería muy fácil acceder a sus datos :-)

Importante: tan pronto como haya abierto un fichero usando un password de encriptación, llame a packfile_password(NULL). Mejor aún, no use esta función. Nunca.

Relacionado con: pack_fopen, load_datafile.
PACKFILE *pack_fopen(const char *filename, const char *mode);
Abre un fichero según el modo, que puede contener cualquiera de los siguientes letras. En vez de estos modos, una de las constantes F_READ, FWRITE, F_READ_PACKED, F_WRITE_PACKED o F_WRITE_NOPACK puede ser usada como el parámetro de modo. Si todo funciona, pack_fopen() devuelve un puntero a una estructura de fichero, y con error, devuelve NULL y almacena el código de error en errno. Un intento de leer un fichero normal en modo comprimido activará errno a EDOM.

Las funciones de ficheros también entienden varios nombres "mágicos" que pueden ser usados por varios motivos. Estos nombres son:

Con estos nombres especiales, los contenidos de un objeto de un fichero de datos o de un fichero añadido pueden ser leídos de modo idéntico que un fichero normal, por lo que cualquiera de las funciones de acceso a ficheros de Allegro (ejemplo: load_pcx() y set_config_file()) pueden ser usadas para leerlos. Sin embargo, no podrá escribir en estos ficheros: sólo pueden ser leídos. Además, debe tener su fichero de datos descomprimido o con compresión por objetos si planea leer objetos individuales (de otra manera, habrá una sobrecarga de búsqueda al ser leído). Finalmente, tenga en cuenta que los tipos de objetos especiales de Allegro no son los mismos que los de los ficheros de los que importe los datos. Cuando importe datos como bitmaps o samples en el grabber, éstos son convertidos a un formato específico de Allegro, pero el marcador de sintaxis de ficheros '#' lee los objetos como trozos binarios raw. Esto significa, que si por ejemplo, quiere usar load_pcx para leer una imagen de un fichero de datos, debería importarla como un bloque binario en vez de un objeto BITMAP.
Relacionado con: file_select, packfile functions, pack_fopen_chunk, packfile_password.

packfile functions

Relacionado con: pack_fopen.
int pack_fclose(PACKFILE *f);
int pack_fseek(PACKFILE *f, int offset);
int pack_feof(PACKFILE *f);
int pack_ferror(PACKFILE *f);
int pack_getc(PACKFILE *f);
int pack_putc(int c, PACKFILE *f);
int pack_igetw(PACKFILE *f);
long pack_igetl(PACKFILE *f);
int pack_iputw(int w, PACKFILE *f);
long pack_iputl(long l, PACKFILE *f);
int pack_mgetw(PACKFILE *f);
long pack_mgetl(PACKFILE *f);
int pack_mputw(int w, PACKFILE *f);
long pack_mputl(long l, PACKFILE *f);
long pack_fread(void *p, long n, PACKFILE *f);
long pack_fwrite(const void *p, long n, PACKFILE *f);
char *pack_fgets(char *p, int max, PACKFILE *f);
int pack_fputs(const char *p, PACKFILE *f);

Todas estas funcionan como las funciones equivalentes stdio, excepto que pack_fread() y pack_fwrite() toman un sólo parámetro de tamaño en vez de ese estúpido sistema de tamaño y num_elements, sólo puede avanzar en un fichero hacia delante desde la posición relativa actual, y pack_fgets() no incluye el retorno de carro en las cadenas que devuelve. Las rutinas pack_i* y pack_m leen y escriben valores de 16 y 32 bits usando los sistemas de orden de Intel y Motorola respectivamente. Tome nota que la búsqueda es muy lenta cuando lea ficheros comprimidos, y que debería ser evitada a no ser que sepa que el fichero no está comprimido.


PACKFILE *pack_fopen_chunk(PACKFILE *f, int pack);
Abre sub-chunks en un fichero. Los chunks son primariamente usados por el código de ficheros de datos, pero pueden serle útiles para sus propias rutinas de ficheros. Un chunk provee una vista lógica de parte de un fichero, que puede ser comprimido como un ente individual y será automáticamente insertado y comprobará los contadores de tamaño para prevenir la lectura después del final del chunk. Para escribir un chunk en un fichero f, use este código:

      /* Asumo que f es un PACKFILE * que ha sido abierto en modo escritura*/
      f = pack_fopen_chunk(f, pack);
      escribe datos en f
      f = pack_fclose_chunk(f);
Los datos escritos en el chunk serán precedidos con dos contadores de tamaño (32 bits, big-endian). Para los chunks sin compresión, éstos serán ajustados al tamaño de los datos del chunk. Para chunks comprimidos (creados al activar la variable pack), el primer tamaño es el tamaño real del chunk, y el segundo será el tamaño negativo de los datos descomprimidos.

Para leer el chunk, use este código:

      /* Asumo que f es un PACKFILE * que ha sido abierto en modo escritura*/
      f = pack_fopen_chunk(f, FALSE);
      lee datos de f
      f = pack_fclose_chunk(f);
Esta secuencia leerá los contadores de tamaño creados cuando el chunk fue escrito, y automáticamente descomprimirá el contenido del chunk si fue comprimido. El tamaño también evitará leer después del final del chunk (Allegro devolverá EOF si intenta esto), y automáticamente ignora los datos no leídos del chunk cuando llamae pack_fclose_chunk().

Los chunks pueden ser anidados unos dentro de otros al hacer llamadas repetidas a pack_fopen_chunk(). Al escribir un fichero, el estado de compresión es heredado del fichero padre, por lo que sólo tiene que activar la variable pack si el fichero padre no fue comprimido pero quiere comprimir los datos del chunk. Si el fichero padre ya está abierto en modo comprimido, activar la variable pack hará que los datos sean comprimidos dos veces: una cuando los datos son escritos en el chunk, y otra cuando el chunk es escrito en el fichero padre.

Relacionado con: pack_fclose_chunk, pack_fopen.
PACKFILE *pack_fclose_chunk(PACKFILE *f);
Cierra un sub-chunk de un fichero, que previamente ha sido obtenido al llamar pack_fopen_chunk().
Relacionado con: pack_fopen_chunk.

Volver al Indice