Amstrad Plus Forum Index

Amstrad Plus
Découverte de la gamme Old et Plus des Cpc d'Amstrad.

 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Packer/UnPacker RLE(suite)

 
Post new topic   Reply to topic    Amstrad Plus Forum Index -> Programmation Cpc -> Crunching
Previous topic :: Next topic  
Author Message
Ast
Administrateur

Offline

Joined: 05 Sep 2014
Posts: 2,977
Masculin
Point(s): 390
Moyenne de points: 0.13

PostPosted: Tue 17 Mar - 20:22 (2020)    Post subject: Packer/UnPacker RLE(suite) Reply with quote

Après une discussion ce matin à propos du packed/unpacker RLE de CNGSOFT, j'ai décidé de coder mon propre cruncher rle.
L'objectif est le suivant, à savoir, produire un cruncher/decruncher RLE, totalement relogeable.

Qu'à cela ne tienne.

Voici, le fruit de mes recherches dont je me fais le plaisir de partager avec vous.

J'ai travaillé, en début d'après-midi sur une première ébauche que je vais vous tenter de vous expliquer.


Le Cruncher (v1)

Code:

;
; RLE Cruncher (v1)
; ---by AsT/iMPACT
; hl=source | de=destination | ix=lenght
; structure -> data,flux
;
   org #a000
;
   ld hl,#c000
   ld de,#4000
   ld ix,#4000
;
   ld b,0 ; compteur de flux
loop_rle   
   ld a,(hl) ; prends 1er octet   
   ld (de),a ; octet
   inc de
nxt_byte
   ld i,a
   ld a,ixl ; si long du fichier=0
   or ixh
   ret z ; alors plus rien a compacter
;
   dec ix
   inc hl
   inc b ; b=b+1
   ld a,b ; si B=0 alors on a 256-1 interation du motif (1er Octet)
   or a ;
   jr z,ba0
;
   ld a,i ;on sauve le 1er octet dans le reg I
;
   ld c,(hl) ; octet 2
   cp c ; compare octet 1 & 2
   jr z,nxt_byte ; si les 2 octets sont égaux alors on mets en place le compteur d'itérations
;
pokeflux
;
   ld a,b ; recupère le compteur et
   ld (de),a ; poke-le après l'octet.
   inc de
   ld b,0 ; raz compteur de flux
   jr loop_rle
;
; Un octet de trop
;
ba0    dec b ; pour garder le flux (Seulement quand b=0, b=255 itérations)
   dec hl ; on revient un octet avant
   jr pokeflux


La base de celui-ci est fort simple. On prends le 1er octet (source), on le poke dans la destination.On prends le second octet (source) et on regarde si cet octet est identique au 1er. Si ce cas est avéré, on mets en route un petit compteur, dans le cas contraire, l'octet 2 devient l'octet 1. il est poké en ram. reste plus qu'à reboucler le tout.

Si je devais expliquer l'algo d'une façon plus simple cela donnerait :

Si le code à compresser était par exemple :

Quote:

00 00 00 00 00 3F FF 8C 8C 8C 8C 09 09


le programme sortira la suite suivante :

Quote:

00 05 3F 01 FF 01 8C 03 09 02


Si je traduis cela de façon compréhensive :

5x 00, puis 1x #3F, 1x #ff, 4x #8c, 2x #09

En gros, la structure est la suivante, octet à poker suivi du nombre de fois à le poker.

Le Décruncher (v1)

Code:

;
; RLE Decruncher (v1)
; ---by AsT/iMPACT
; hl=source | de=destination
; structure -> data,flux
; quand 00,00 fin du fichier
;
   org #a100
;
   ld hl,#4000
   ld de,#C000
;
decrunch
   ld c,(hl) ; 1er octet
   inc hl
   ld b,(hl) ; 2ème octet
   inc hl

   ld a,c ; on teste si les 2 octets sont à zéro
   or b
   ret z ; si 00,00 alors fin
;
   ld a,c ; on récupère la valeur du 1er octet
;
flux
   ld (de),a ; on le poke b fois
   inc de
   djnz flux
   jr decrunch
;


Le code du décruncher fait la même chose à l'envers, à savoir lire l'octet puis le nombre de fois que cet octet est répété.
La fin est détectée quand le programme rencontre "00,00"

J'aurais pu m'arrêter là, mais, je me suis dis que pour les répétitions x il y avait 2 octets occupés pour un seul octet sorti.
La solution passait donc, par un flag, ou plutôt un identifiant de boucle.

La méthode choisie, je cherche dans le code à compresser parmi 256 valeurs possibles (0-255), la valeur qui n'existe pas dans le code à compresser.

Recherche du Flag (ou recherche de l'octet non utlisé dans les datas à cruncher)

Code:

;
; Recherche de Flag
; -- By Ast/iMPACT
; HL=Source | BC=Longueur
;
   org #A200
   
   ld e,0 ; flag de départ (0-255)
;
stream
   ld hl,#c000 ; adresse de départ
   ld bc,#4000 ;longueur du fichier à compresser
;
bouc
   ld a,(hl) ; Lis octet
   cp e      ; on compare l'octet au flag contenu dans le Reg E
   jr z,found ; l'octet est le même que le flag, on passe au flag suivant (e=e-1)
   inc hl
   dec bc
   ld a,b
   or c
   jr nz,bouc ; on boucle tant que l'octet et le flag ne sont pas égaux durant la longueur déterminée par BC
diff   ld a,e ; E=octet n'existant pas dans le fichier à compresser. A=E
        ld (#36),a ; adresse où sera poké ce flag
   ret

found
   dec e ; si l'octet est le même que le flag, on change la valeur du flag
   jr nz,stream ; et on retourne au début rechercher un nouveau flag
   ret


Quand le flag est trouvé, il est directement poké à l'adresse #36.

Le Cruncher (v2)

Code:

;
; RLE Cruncher (v2)
; ---by AsT/iMPACT
; hl=source | de=destination | ix=lenght
; structure -> data,flag,flux
;
flag equ #36
;
crunch
   ld hl,#c000
   ld de,#4000
   ld ix,#4000
;
   ld b,0 ; compteur de flux
loop_rle   
   ld a,(hl) ; prends 1er octet   
   ld (de),a ; octet
   inc de
nxt_byte
   ld i,a ; i=a=1er octet
   ld a,ixl ; si long du fichier=0
   or ixh
   ret z ; alors plus rien a compacter
;
   dec ix
   inc hl
   inc b ; b=b+1
   ld a,b ; si b=0 alors on a 256-1 interation du motif (1er Octet)
   or a
   jr z,ba0
;
   ld a,i ; recupère valeur de a (1er octet)
;
   ld c,(hl) ; octet 2
   cp c ; compare octet 1 & 2
   jr z,nxt_byte
;
   ld a,b
   dec a
   jr z,pokeone
;
pokeflux
;
   ld a,(flag)
   ld (de),a
   inc de
;
pokebyte
;
   ld a,b
   ld (de),a
   inc de
   jr pokeone
;
; Un octet de trop
;
ba0    dec b ; pour garder le flux
   dec hl
   jr pokeflux
;
pokeone   ld b,0
   jr loop_rle


Si le code à compresser était par exemple

Quote:

00 00 00 00 00 3F FF 8C 8C 8C 8C 09 09


le programme sortira la suite suivante : (avec #ae comme flag)

Quote:

00 AE 05 3F FF 8C AE 04 09 AE 02


Si je traduis cela de façon compréhensive :

Octet #00, flag #AE donc répétition 5x
Octet #3F, pas de flag on passe au suivant
Octet #FF, pas de flag on passe au suivant
Octet #8c, flag #AE donc répétition 4x
Octet #09, flag #AE donc répétition 2x
...

Le Décruncher (v2)

Code:

;
; RLE Decruncher (v2)
; ---by AsT/iMPACT
; hl=source | de=destination
; structure -> data,flag,flux
; quand 00,00 fin du fichier
;
   org #a100
;
flag    equ #36
;
   ld hl,#4000 ; startadr
   ld de,#C000 ; destination
   ld a,(flag) ; le flag a été déterminé par la routine recherche de flag
   ld ixl,a
;
decrunch
   ld c,(hl) ;octet 1
   inc hl
   ld b,(hl) ; flag ou octet 2
   inc hl

   ld a,c ;Est ce que l'octet 1 est l'octet 2 sont à zéro ?
   or b ;
   ret z ; si 00,00 alors fin
;
   ld a,b ; est ce que l'octet 2 est le flag ?
   cp ixl ; #fd
   jr nz,noflux ; s'il n'y a pas de répétition on poke seulement l'octet (sans répétition)
;
   
   ld b,(hl) ; flux
   inc hl
;
   ld a,c ; on récupère l'octet à répéter
;
flux
   ld (de),a ;on poke en mémoire
   inc de
   djnz flux ;on boucle x fois
;
   jr decrunch
;
; Pas de répétion ? On poke juste l'octet
;
noflux
   ld a,c ; recupère l'octet en cours (1er octet)
   ld(de),a ;on poke
   inc de
    dec hl ; on revient 1 octet avant
;
   jr decrunch
;


Le décruncher joue son rôle, comme expliqué plus haut.
La fin est détectée quand le programme rencontre "00,00"

Quoiqu'il en en soit :

- Les méthodes 1 & 2 sont relogeables.
- La vitesse de compression/décompression est rapide.

Il faut toutefois rajouter 2 octets de plus en fin de fichier (à zéro) afin que le marqueur "fin" soit en place.
Par exemple, si le fichier compressé fait #19F0 octets, une fois sauvegardé, il devra faire #19F2 octets, les deux derniers octets devant être à zéro.


Je reste néanmoins à votre disposition pour toute autre méthode, routine proposée ici, dont je suis friand (je dois bien l'avouer!)


Article correspondant, Packer/UnPacker by CNGSOFT
_________________
Ast/iMP4CT

"Par le pouvoir du crâne ancestral...."


Back to top
Publicité






PostPosted: Tue 17 Mar - 20:22 (2020)    Post subject: Publicité

PublicitéSupprimer les publicités ?
Back to top
Display posts from previous:   
Post new topic   Reply to topic    Amstrad Plus Forum Index -> Programmation Cpc -> Crunching All times are GMT + 2 Hours
Page 1 of 1

 
Jump to:  

Index | Administration Panel | Create a forum | Free support forum | Free forums directory | Report a violation | Cookies | Charte | Conditions générales d'utilisation
Powered by phpBB © 2001, 2005 phpBB Group