;LZ3KPA: Packer para el proyecto de fin de carrera ; (M‚todo 1 - LZ3K > LZ greedy con diccionario de 3K) ; ; Versi¢n 1.2 ; ; Realizado en lenguaje ensamblador, se compila con NASM ; ; - El programa maestro de Windows, para transmitir permite seleccionar ; un archivo visualmente, entonces graba el nombre del archivo con su unidad ; y path delante y acabado en 0 en otro archivo llamado ENTRADA.ARC, que se ; coloca en el mismo path del programa, donde tambi‚n est situado este m¢dulo ; de compresi¢n. ; ; - Este modulo de compresi¢n tiene como misi¢n abrir el archivo mencionado ; en ENTRADA.ARC y comprimirlo en el archivo de salida SALIDA.CMP, que queda ; listo para ser enviado por el puerto serie ;******************************* org 256 ;Programa start mov ah,3ch ;Funci¢n para crear archivo xor cx,cx ;Atributos a 0 mov dx,nameout ;Nombre del archivo: SALIDA.CMP int 33 ;Crear archivo de salida jnc noerror01 ;Si no hay error, continuar mov ax,4c01h ;C¢digo de error 1 int 33 ;Salir a Windows noerror01 mov [handleout],ax ;Salvar handle de SALIDA.CMP mov ax,3d00h ;Funci¢n para abrir archivo mov dx,namepath ;Nombre del archivo a abrir int 33 ;Abrir ENTRADA.ARC jnc noerror02 ;Si no hay error, continuar mov ax,4c02h ;C¢digo de error 2 int 33 ;Salir a Windows noerror02 xchg ax,bx ;Handle de ENTRADA.ARC en bx mov ah,3fh ;Funci¢n para leer de archivo mov cx,400 ;N£mero m ximo de bytes a leer mov dx,pathbuffer ;Posici¢n donde se escriben los bytes int 33 ;Leer bytes jnc noerror03 ;Si no hay error, continuar mov ax,4c03h ;C¢digo de error 3 int 33 ;Salir a Windows noerror03 mov si,dx ;Apuntar al nombre de archivo mov dx,1 ;Abrir archivo existente, no crear xor bx,bx ;Modo de acceso solo lectura xor cx,cx ;Sin atributos mov ax,716ch ;Funci¢n para crear o abrir archivo ; usando nombres largos int 33 ;Abrir archivo jnc noerror05 ;Si no hay error, continuar mov ax,4c05h ;C¢digo de error 5 int 33 ;Salir a Windows noerror05 mov [handlein],ax ;Salvar handle del archivo de entrada xchg ax,bx ;Handle en bx mov ah,3fh ;Funci¢n para leer mov cx,3072 ;3K van a ser leidos mov dx,buffer ;En el buffer int 33 ;Leer call copytoend ;Copiar los primeros 128bytes al final add dx,ax ;Final de bytes leidos cmp ax,cx ;Si se leen menos de 6K jnc nosmallfile mov [EOF],dx ;Marcar End of File jmp short bucle ;Y no poner readedge nosmallfile add ax,buffer-128 ;Readedge > una vez procesado hasta mov [readedge],ax ; aqu¡, tenemos que leer 128 nuevos ; bytes ;La compresi¢n comienza aqu¡ bucle inc word [maxdistance] ;Aumentar la distancia m xima de ; b£squeda de coincidencia en 1 byte mov si,[current] ;Posici¢n del byte actual cmp si,[EOF] ;Verificar si hemos llegado al final jnz noEOFfound ; del archivo, si no es as¡ saltar mov ax,[untagged_literals] and ax,ax ;Comprobar si quedan literales jz nomoreflush ; pendientes de marcar call tagliterals ;Marcarlos nomoreflush call puttag1 ;Poner call puttag0 ; c¢digo call puttag0 ; de call puttag0 ; fin call puttag0 ; de call puttag1 ; archivo call puttag1 ; correspondiente call puttag1 ; a 10000111 call puttag0 ;Rellenar con ceros para que se call puttag0 ; escriba el £ltimo tag-byte y se call puttag0 ; vac¡en los literales que haya call puttag0 ; pendientes call puttag0 ;con 7 nos aseguramos de ello call puttag0 call puttag0 mov ah,40h ;Funci¢n de escritura mov bx,[handleout] ;Handle del archivo de salida mov cx,[currentoutput] ;Puntero de escritura mov dx,outbuffer ;Direcci¢n del buffer de escritura sub cx,dx ;N£mero de bytes a escribir int 33 ;Vaciar el buffer de escritura end mov ax,4c00h ;Sin error int 33 ;Salir a Windows noEOFfound push si ;Almacenar posici¢n actual en la pila lodsb ;Leer byte cmp si,endbuffer ;Si la siguiente posici¢n llega al jnz nowrap00 ; final del buffer mov si,buffer ;colocarla al principio nowrap00 mov [current],si ;actualizar posici¢n de byte procesado cmp si,[readedge] ;si hemos llegado al l¡mite de lectura jnz noedgecrossed ;hay que leer un nuevo bloque, si no ;se contin£a pusha ;Guardar registros mov cx,128 ;Bytes a leer / avanzar mov dx,si ;Se va a leer en add dx,cx ; la posici¢n actual + 128 cmp dx,endbuffer ;¨esto est al final del buffer? jnz nowrap02 ;NO: saltar mov dx,buffer ;SI: colocar al comienzo nowrap02 mov ah,3fh ;Funci¢n de lectura mov bx,[handlein] ;Handle del archivo de entrada int 33 ;Leer 128 bytes jnc noerror04 ;Si no hay error, continuar mov ax,4c04h ;C¢digo de error 4 int 33 ;Salir a Windows noerror04 cmp dx,buffer ;Si hemos leido en el principio jnz nocopytoend call copytoend ;Pasarlo al final tambi‚n nocopytoend cmp ax,cx ;Verificar si se han leido 128 bytes jz EOFnotFOUND ;Si es as¡ saltar EOFFOUND add dx,ax ;Si se han leido menos, colocar mov [EOF],dx ; la marca de fin de archivo jmp short NoReadEdge; y no fijar un nuevo readedge EOFnotFOUND mov [readedge],dx ;Actualizar readedge NoReadEdge sub word [maxdistance],128 ;Actualizar maxdistance popa ;Restaurar registros noedgecrossed pop si ;Byte en al, si=current mov bl,al mov bh,0 add bx,bx ;BX=AL*2 mov bp,[bx+prev] ;Buscar £ltima posici¢n del byte en ; el buffer mov [bx+prev],si ;Actualizar £ltima posici¢n mov cx,si ;CX = distancia al previo, para sub cx,bp ; poner en prevbuff ja nowrap03 ;Si la distancia es 0 o negativa add cx,3072 ;Ajustarla nowrap03 ;CX=distancia entre si y bp mov bx,si mov [bx+si],cx ;Actualizar prevbuff dec byte[codepaired] ;Si el byte ya est comprimido en un jns near bucle ; codepair, no hace falta buscar inc byte[codepaired] ; coincidencias and bp,bp ;Si bp es 0, el byte es un literal jz near SETLITERAL_clearprevbuff ; colocarlo cmp al,[bp] ;Si el previo no coincide, era falso jnz near SETLITERAL_clearprevbuff ;Por lo tanto > literal mov byte [max_match_lenght],0 ;Iniciar distancia m xima hallada ; hasta el momento ;Entrada al bucle de b£squeda > Distancia acumulada en CX ; > Posici¢n del siguiente a compara en BP loop00 cmp [maxdistance],cx ; si la distancia sobrepasa el l¡mite jc exitsearchloop ;dejar de buscar push si ;Guardar posici¢n actual mov di,bp ;SI=position_temp_curr ;DI=position_temp_comp mov dl,0 ;DL=M xima longitud de coincidencia actual keepmatching cmpsb ;Comparar bytes jnz nomore ;Si no coinciden, salir de esta comparaci¢n inc dl ;Si coinciden, incrementar n£mero de bytes js nomore ;Si es 128, no seguir buscando cmp si,[EOF];Si hemos llegado al final del archivo, jnz keepmatching ; tampoco, en caso contrario seguir nomore cmp [max_match_lenght],dl ;Comparar coincidencia con la ; m xima hasta ahora jnc trynext ;Si no la supera, pasar a la ; siguiente mov [max_match_lenght],dl ;Si la supera, guardar la ; longitud mov [max_match_distance],cx ; y la distancia del match cmp dl,128 ;si es de longitud m xima jz exitsearchmax ; dejar de buscar trynext mov di,bp ;Para acceder a prevbuff[bp] add cx,[bp+di] ;Acumular distancia sub bp,[bp+di] ;Hallar nueva posici¢n cmp bp,buffer ;Ver se pasa del buffer jnc nowrap07 ;Si no, saltar add bp,3072 ; Si se pasa, ajustar nowrap07 pop si ;Recuperar posici¢n actual jmp short loop00 ;Repetir el bucle de b£squeda exitsearchmax pop si ;Limpiar pila exitsearchloop cmp [max_match_lenght],byte 2 ;Si la distancia es menor jc near SETLITERAL ; a 2, poner un literal jnz setcodepair ; si es mayor, poner un codepair cmp [max_match_distance],word 255 ;Si es = 2, depende de jnc SETLITERAL ; la distancia. Mayor a 255 > literal setcodepair mov cx,[untagged_literals] ;Ver si hay literales sin marcar jcxz notagliterals ;Si no, saltar call tagliterals ;Marcar los literales pendientes notagliterals mov al,[max_match_lenght] ;Fijar el n£mero de dec ax ; bytes que no deben mov [codepaired],al ; realizar la b£squeda call puttag1 ;Codificar un 1 mov bx,[max_match_distance] ; BX=distancia bsr cx,bx ;N£mero de bits que van a ser ; codificados btr bx,cx ;Eliminar el bit mayor bt cx,3 ;Colocar el bit 3 del n£mero de bits call puttagbit ; de la distancia bt cx,2 ;Excitar flag C seg£n el bit 2 call puttagbit ;Codificar bit bt cx,1 ;Ahora el 1 call puttagbit ;Codificar bit bt cx,0 ;Y por £ltimo el 0 call puttagbit ;Codificar bit jcxz x_xdone ;Si no hay que poner mas bits, la ; distancia ya est hecha shl bx,1 ;Adaptar bx putx_x bt bx,cx ;Averiguar bit de la distancia call puttagbit ;Codificarlo loop putx_x ;Colocarlos todos x_xdone mov bl,[max_match_lenght] ; xor bh,bh ;BX = longitud de la coincidencia dec bx ;Codificar uno menos, ya que el minimo ; es 2 bsr cx,bx ;N£mero de bits a codificar btr bx,cx ;Eliminar el bit mayor bt cx,2 ;Colocar los 3 bits del n£mero de bits call puttagbit ; de la longitud bt cx,1 ;Al igual que se hizo antes con los call puttagbit ; de la distancia bt cx,0 ;éltimo bit... call puttagbit ;Codificarlo jcxz y_ydone ;Saltar si no hay bits que colocar shl bx,1 ;Adaptar bx puty_y bt bx,cx ;Excitar flag C call puttagbit ;Codificar bit loop puty_y ;Hacerlo con todos y_ydone jmp bucle ;Volver al bucle principal SETLITERAL_clearprevbuff mov [bx+si],word 3071 ;Colocar en prevbuff una distancia ; tal que se pasa y no sigue buscando SETLITERAL mov bx,[untagged_literals] ; N£mero de literales sin ; marcar and bx,bx ;Comprobar si es el primero jnz nofirstuntagged ;Si no lo es saltar mov [untagged_literal_start],si ; Si es el primero, ; colocar direcci¢n de comienzo de ; los literales nofirstuntagged inc bx ;Incrementar n£mero de literales mov [untagged_literals],bx ;Guardarlo cmp bx,261 ;Comprobar si se ha llegado al m ximo jnz y_ydone ;Si no, volver al bucle principal push word bucle ;Si se llega al m ximo, ejecutar ; tagliterals y volver al bucle tagliterals pusha ;Guardar registros mov bx,[untagged_literals] ; N£mero de literales sin marcar mov bp,bx ;Tambi‚n en BP cmp bx,7 ;Si es menor que 7 jc plain_literals ;Ir a plain_literals call puttag1 ;Si no call puttag1 ;Colocar los 3 bits que indican call puttag1 ; cadena de literales sub bx,6 ;Restar 6 al n£mero de bytes bsr cx,bx ; que va a ser codificado btr bx,cx ;Eliminar el bit mayor bt cx,2 call puttagbit ; Colocar el n£mero de bits bt cx,1 ;del n£mero de bits de la cadena call puttagbit bt cx,0 jcxz lastbit ;El £ltimo bit debe dejarse para el ; final call puttagbit dec cx ;Decrementar cx jz lastbit ;El £ltimo bit debe dejarse para el ; final puty bt bx,cx ;Coger bit call puttagbit ;Codificarlo loop puty ;Repetir con todos lastbit mov ax,[tagged_literals] ;Ver si hay literales ya and ax,ax ; marcados jnz noanotherstart ;Si los hay, no cambiar el comienzo mov dx,[untagged_literal_start] ;Coger el comienzo de los ; no marcados mov [tagged_literal_start],dx ; Y colocarlo en el comienzo ; de los marcados noanotherstart add [tagged_literals],bp ;Incrementar n£mero de bytes marcados xor ax,ax ;AX=0 bt bx,ax ;éltimo bit por colocar call puttagbit ;Codificarlo mov [untagged_literals],ax ;Literales sin marcar=0 popa ;Restaurar registros ret ;Volver plain_literals mov ax,[tagged_literals] ;Ver si ya hay literales and ax,ax ; marcados jnz noanotherstart2 ;Si los hay, no cambiar el comienzo mov dx,[untagged_literal_start] ;No hay: Poner el comienzo ; de los no marcados mov [tagged_literal_start],dx ; en el de los marcados noanotherstart2 inc word [tagged_literals] ;Incrementar n£mero de ; literales marcados call puttag0 ;Codificar un 0 inc word [untagged_literal_start] ;Incrementar comienzo de ; literales sin marcar dec word [untagged_literals];Decrementar n£mero de ; literales sin marcar jnz plain_literals ;Repetir mientras queden popa ;Restaurar registros ret ;Volver copytoend pusha ;Guardar registros mov si,buffer ;Origen: comienzo del buffer mov di,endbuffer ;Destino: final del buffer mov cx,64 ;64 words rep movsw ;Copiar popa ;Restaurar registros ret ;Volver puttag0 clc ;Flag C = 0 jmp short puttagbit ;Ir a poner el bit puttag1 stc ;Flag C = 1 puttagbit pusha ;Guardar registros mov dl,[tag_bits] ;Coger tag_bits actuales adc dl,dl ;Colocar nuevo bit jnc nonexttagbyte ;Si no sale el marker bit, saltar mov al,dl ;Si sale, colocar el al call writebyte ;Y escribir el byte mov cx,[tagged_literals] ;Comprobar si hay literales ; marcados jcxz notaggedliterals ; Si no, saltar mov si,[tagged_literal_start] ;Si los hay, poner el origen ; en si putliterals lodsb ;Cargar literal marcado call writebyte ;Escribirlo cmp si,endbuffer ;Si llegamos al final del buffer jnz nowrap08 mov si,buffer ;Colocar al principio nowrap08 loop putliterals ;Hacer todos los literales marcados mov [tagged_literals],cx ;Ahora literales marcados=0 notaggedliterals mov dl,1 ;Nuevo marker-bit nonexttagbyte mov [tag_bits],dl ;Actualizar tag_bits popa ;Restaurar registros ret ;Volver writebyte pusha ;Guardar registros mov di,[currentoutput] ;Posici¢n actual del puntero de ; escritura stosb ;Escribir el byte en memoria cmp di,endoutbuff ;¨El puntero llega al final? jnz nolastbyte ;NO: Saltar mov ah,40h ;Funci¢n de escritura mov bx,[handleout] ;Handle del archivo de salida mov cx,32768 ;N£mero de bytes mov dx,outbuffer ;Buffer de escritura int 33 ;Escribir bytes jnc noerror07 ;Si no hay error, continuar mov ax,4c07h ;C¢digo de error 7 int 33 ;Salir a Windows noerror07 mov di,dx ;Colocar puntero al principio nolastbyte mov [currentoutput],di ; Actualizar puntero de escritura popa ;Restaurar registros ret ;Volver ;FIN DEL PROGRAMA ;******************************* ;Variables con valores iniciados EOF dw 65535 ;(Basta con que est‚ fuera del buffer) current dw buffer ;Posici¢n de memoria siendo procesada namepath db "ENTRADA.ARC",0 nameout db "SALIDA.CMP",0 tagged_literal_start dw 0 ;Comienzo de los literales marcados tagged_literals dw 0 ;N£mero de literales marcados untagged_literal_start dw 0 ;Comienzo de los literales sin marcar untagged_literals dw 0 ;N£mero de literales sin marcar tag_bits db 1 ;Tag byte en construcci¢n codepaired db 0 ;N£mero de bytes a saltar currentoutput dw outbuffer maxdistance dw -1 ;Hasta cuanto podemos retroceder al buscar ; un match prev times 256 dw 0 ;******************************* ;******************************* section .bss ;Variables sin iniciar handleout resw 1 ;Handle del archivo de salida handlein resw 1 ;Handle del archivo de entrada max_match_lenght resb 1 ;M xima l¢ngitud de match hallado max_match_distance resw 1 ;Distancia a la que se encuentra dicho match readedge resw 1 ;L¡mite de proceso hasta volver a leer un ; bloque de 128 bytes pathbuffer resb 400 ;Aqu¡ se almacena la posici¢n del £ltimo ; byte de un determinado tipo buffer EQU 8192 endbuffer EQU buffer+3072 prevbuff EQU 16384 outbuffer EQU 28672 endoutbuff EQU outbuffer+32768 ;errorlevels: ; ; 0 - OK, no error ; 1 - No se puede crear SALIDA.CMP ; 2 - No se puede abrir ENTRADA.ARC ; 3 - No se puede leer ENTRADA.ARC ; 4 - Error de lectura ; 5 - No se puede abrir el archivo de entrada ; 7 - Error de escritura