/* */

20 de mayo de 2008

TP - Compresor Huffman

.
Análisis del Descompactador

Para descomprimir los archivos la estrategia será la siguiente:

  • Recomponer el árbol Huffman original.
  • Recorrer leyendo "bit por bit" el archivo codificado y por cada bit leido bajar un nivel (comenzando desde la raíz) del árbol, a izquierda o a derecha según el bit leido sea 0 o 1. Así hasta llegar a una hoja, lo cual nos indicará que llegamos al caracter que debemos restaurar.
  • Cada caracter "restaurado" escribirlo en el nuevo archivo de salida que será el mismo que el que se comprimió con el compresor.
Analicemos el código.

szunzip.pas
   1:
2:uses untSz,untSzzip,untSzunzip;
3:
4:var
5: archDat:FByte; archCod:FByte;
6: b:byte;
7: arr:TArray;
8: p,aux:PNodo;
9: nBytesOri:comp;
10: nomArch:string;
11: i:integer;
12:
13:begin
14:
15: if( paramCount()>0 ) then begin
16: nomArch:=paramStr(1);
17: end else begin
18: write('ERROR: Debe especificar el archivo ');
19: writeln('a descomprimir');
20: writeln('USAGE: szunzip nombreArchivo');
21: exit;
22: end;
23:
24: inicializarArray(arr);
25:
26: // levanto el archivo len
27: nBytesOri:=leerLen(arr,nomArch+EXTENSION_LEN);
28:
29: // levanto el archivo .cod al array
30: subirArchivoCod(nomArch+EXTENSION_COD,arr);
31:
32: // armo la lista enlazada
33: p:=crearLista(arr);
34:
35: // armo el arbol
36: listaToArbol(p);
37:
38: grabarArchivo(p,nomArch,nomArch+EXTENSION_DAT
39: , nBytesOri);
40:end.
41:

El programa szunzip.pas recibe en línea de comandos el nombre del archivo original. Por ejemplo: dibujo.bmp. Con este nombre podrá obtener los nombres de los archivos dibujo.szlen, dibujo.szcod y dibujo.szzip.

En la línea 15 verificamos que se haya pasado el nombre del archivo como argumento en línea de comandos y (si no lo pasaron) mostramos un mensaje de error.

En la línea 27 leemos el archivo .szlen con la función leerLen que retorna el tamaño original del archivo. Recordemos que este archivo es un archivo de registros RLen y cada registro contiene la cantidad de ocurrencias de cada caracter que contenia el archivo original.

En la línea 30 "restauramos" el array leyendo el archivo .szcod. Recordemos que este es un archivo de bytes (de tipo FByte) donde el primer byte indica un caracter (valor de 0 a 255), el segundo byte indica el nCod para ese caracter y los siguientes m bytes representan el código Huffman (cod) con el que se codificó al caracter. Así con todos los caracteres codificados.

El procedimiento subirArchivoCod debe leer el archivo .szcod y completar los campos nCod y cod del array arr.

Teniendo el array cargado podemos crear la lista y el árbol Huffman con la función crearLista y el procedimiento listaToArbol que ya analizamos (y programamos) anteriormente (ver líneas 33 y 36).

Por último el procedimiento grabarArchivo (línea 38) lee el archivo .szzip y reescribe el archivo original procesando cada byte (y cada bit) leido.


Analicemos la unit untSzunzip.pas donde se definen e implementan las funciones y procedimientos que utiliza szunzip.pas.

untSzunzip.pas
   1:
2:unit untSzunzip;
3:
4:interface
5: uses untSz;
6:
7: // lee el archivo nomArchLen de tipo FLen y carga
8: // el array con los datos que levanta del archivo.
9: // Retorna la cantidad de caracteres que tenia
10: // el archivo original
11: function leerLen(var arr:TArray
12: ;nomArchLen:string):comp;
13:
14: // lee el archivo nomArch de tipo FByte respetando
15: // el criterio con el que se grabo: un byte indica
16: // el caracter, luego un byte indica el nCod y
17: // luego m bytes indican el cod, sube estos datos
18: // al array arr
19: procedure subirArchivoCod(nomArch:string
20: ;var arr: TArray);
21:
22: // avanza por las ramas del arbol hasta llegar a
23: // una hoja, asi obtiene el caracter original que
24: // corresponde al codigo huffman leido (esta
25: // funcion se provee, no es necesario programarla)
26: procedure procesarBits(var arch:FByte; p:PNodo
27: ;var aux: PNodo
28: ;buffer: byte
29: ;var nBytesOri:comp);
30:
31: // recorre el archivo nomArchDat de tipo FByte y
32: // por cada byte lo manda a procesar
33: // a procesarBits. Este procedimiento utiliza
34: // el procedimiento procesarBits
35: procedure grabarArchivo(p: PNodo; nomArch
36: ,nomArchDat: string
37: ;nBytesOri:comp);
38:
39:implementation
40:
41:// :
42:// :
43:// :
44:
45:end.
46:

La función leerLen y el procedimiento subirCod ya fueron explicados.

En la línea 26 aparece la definición del procedimiento procesarBits (cuya implementación se provee con el enunciado). Este procedimiento recibe un byte (leido desde el archivo .szzip) y procesa sus bits, bit por bit desplazándose correctamente por el árbol Huffman hasta llegar al caracter codificado en ese byte. Graba el el caracter en el (nuevo) archivo original y (si quedan bits por procesar en el byte) repite la operación hasta agotar los 8 bits.

El procedimiento grabarArchivo (línea 35) debe recorrer el archivo .szzip y por cada byte leido invocar a procesarBits para que recorra el árbol y recupere (y grabe) el caracter decodificado en el archivo original.




.............................................




.