compression/codage.pas

426 lines
7.8 KiB
Plaintext
Raw Permalink Normal View History

2016-03-07 17:51:00 +01:00
program codage;
uses crt,dos,math;
type
anagramme=^cellule1;
cellule1=record
octet:byte;
prec:anagramme;
suiv:anagramme;
end;
decalage=array of anagramme;
catalogue=array[0..255] of byte;
fichier=array of byte;
bit=0..1;
liste=^cellule2;
cellule2=record
octet:byte;
freq:longword;
suiv:liste;
gauche:liste;
droite:liste;
end;
tableau=array[0..255] of liste;
sauvegarde=array of liste;
final=array[0..255] of array of bit;
var f:fichier;a:anagramme;d:decalage;taille,p:longword;l:liste;fin:final;longueur:byte;s:sauvegarde;chemin:string;
procedure importer(var p:anagramme; var taille:longword; var chemin:string);
var f:file;p1:anagramme;
begin
write('Chemin du fichier : ');
readln(chemin);
if chemin[length(chemin)]=' ' then delete(chemin,length(chemin),1);
assign(f,chemin);
reset(f,1);
new(p);
p1:=p;
writeln('Importation...');
while not eof(f) do
begin
new(p1^.suiv);
p1^.suiv^.prec:=p1;
p1:=p1^.suiv;
blockread(f,p1^.octet,1);
end;
taille:=filesize(f);
close(f);
p:=p^.suiv;
p1^.suiv:=p;
p^.prec:=p1;
end;
function EstSuperieur(p1,p2:anagramme;longueur:longword):boolean;
var pa,pb:anagramme;i:longword;
begin
i:=1;
pa:=p1;
pb:=p2;
while ((i<=longueur) and (pa^.octet=pb^.octet)) do
begin
pa:=pa^.suiv;
pb:=pb^.suiv;
i:=i+1;
end;
if pa^.octet>pb^.octet then EstSuperieur:=true else EstSuperieur:=false;
end;
function inserer(p:anagramme;t:decalage;debut,fin,taille:longword):longword;
var milieu:longword;
begin
if fin-debut=0 then inserer:=debut
else
begin
milieu:=(debut+fin) div 2;
if EstSuperieur(t[milieu],p,taille) then
inserer:=inserer(p,t,debut,milieu,taille)
else
inserer:=inserer(p,t,milieu+1,fin,taille);
end;
end;
procedure reindex(var t:decalage;p:anagramme;i,taille:longword; var position:longword);
var j,k:longword;
begin
j:=inserer(p,t,0,i,taille);
setlength(t,i+1);
if j<=position then position:=position+1;
for k:=i downto j do t[k+1]:=t[k];
t[j]:=p;
end;
procedure tabler(var t:decalage; var p:anagramme;taille:longword; var position:longword);
var i:longword;x:byte;
begin
x:=1;
setlength(t,1);
t[0]:=p;
position:=0;
for i:=1 to taille-1 do
begin
p:=p^.suiv;
reindex(t,p,i,taille,position);
if ((i+1)*100) div taille >= x then
begin
writeln(x,'% des décalages indexés');
x:=x+1;
end;
end;
end;
procedure prefixe(n:longword; var p:anagramme; var i:integer);
var p1:anagramme;
begin
i:=0;
new(p);
p1:=p;
repeat
begin
i:=i+1;
new(p1^.suiv);
p1^.suiv^.prec:=p1;
p1:=p1^.suiv;
p1^.octet:=((n-(trunc(power(2,7*i))*(n div trunc(power(2,7*i))))) div trunc(power(2,7*(i-1))))*2+1;
end;
until n div trunc(power(2,7*i))=0;
p:=p^.suiv;
p1^.suiv:=p;
p^.prec:=p1;
p^.octet:=p^.octet-1;
p:=p^.prec;
end;
procedure dernier(var d:decalage);
var i:longword;
begin
for i:=0 to length(d)-1 do d[i]:=d[i]^.prec;
end;
procedure transformer(n:longword;d:decalage;taille:longword;var f:fichier);
var i:longword;j:integer;p:anagramme;
begin
setlength(f,0);
prefixe(n,p,j);
writeln('Position du motif original fixée à ',n,', codée sur ',j,' octet(s)');
(*Écriture du préfixe...*)
setlength(f,j+taille);
for i:=0 to j-1 do
begin
f[i]:=p^.octet;
p:=p^.prec;
end;
writeln('Écriture de la séquence codée...');
dernier(d);
for i:=0 to taille-1 do
begin
f[i+j]:=d[i]^.octet;
dispose(d[i]);
end;
setlength(d,0);
end;
procedure coder(var p:fichier;taille:longword);
var ref,car:catalogue;i:longword;j,k,l:byte;f:fichier;
begin
setlength(f,taille);
for i:=0 to 255 do ref[i]:=i;
car:=ref;
for i:=0 to taille-1 do
begin
j:=p[i];
f[i]:=ref[j];
l:=car[ref[j]];
for k:=ref[j] downto 1 do
begin
car[k]:=car[k-1];
ref[car[k]]:=k;
end;
car[0]:=l;
ref[l]:=0;
end;
p:=f;
setlength(f,0);
end;
procedure trier(var l:liste);
var l1,l2:liste;
begin
l1:=l;
if l<>nil then
begin
while l1^.suiv<>nil do
begin
if l1^.suiv^.freq<l^.freq then
begin
l2:=l1^.suiv;
l1^.suiv:=l2^.suiv;
l2^.suiv:=l;
l:=l2;
l1:=l;
end;
l1:=l1^.suiv;
end;
trier(l^.suiv);
end;
end;
function inserer2(var l:liste; var l1:liste):liste;
begin
if l=nil then
begin
l1^.suiv:=nil;
inserer2:=l1;
end
else
begin
if l1^.freq<=l^.freq then
begin
l1^.suiv:=l;
inserer2:=l1;
end
else
begin
l^.suiv:=inserer2(l^.suiv,l1);
inserer2:=l;
end;
end;
end;
procedure branche(var l:liste;b:bit;var fin:final);
var aux:array of bit;
begin
if ((l^.gauche=nil) and (l^.droite=nil)) then
begin
aux:=fin[l^.octet];
setlength(aux,length(aux)+1);
aux[length(aux)-1]:=b;
fin[l^.octet]:=aux;
setlength(aux,0);
end
else
begin
branche(l^.gauche,b,fin);
branche(l^.droite,b,fin);
end;
end;
procedure arbre(var l:liste;var fin:final);
var l1:liste;
begin
if l^.suiv<>nil then
begin
new(l1);
l1^.gauche:=l;
l1^.droite:=l^.suiv;
l1^.freq:=l^.freq+l^.suiv^.freq;
branche(l1^.gauche,0,fin);
branche(l1^.droite,1,fin);
l:=inserer2(l^.suiv^.suiv,l1);
arbre(l,fin);
end;
end;
procedure nombrelong(n:longword; var nombre:fichier);
var i:longword;
begin
i:=1;
setlength(nombre,0);
repeat
begin
setlength(nombre,i);
nombre[i-1]:=((n-(trunc(power(2,7*i))*(n div trunc(power(2,7*i))))) div trunc(power(2,7*(i-1))))*2+1;
i:=i+1;
end;
until n div trunc(power(2,7*(i-1)))=0;
nombre[0]:=nombre[0]-1;
end;
function nouv_chemin(chemin:string):string;
var i:byte;s:string;
begin
s:=chemin;
i:=length(chemin);
while s[i]<>'.' do i:=i-1;
delete(s,i,length(chemin)-i+1);
nouv_chemin:=s+'.cmp'
end;
procedure ecrire(fin:final;p:fichier;taille:longword;s:sauvegarde;longueur:byte;chemin:string);
var f:file;i,m:longword;j,k:byte;nombre:fichier;
begin
assign(f,nouv_chemin(chemin));
rewrite(f,1);
writeln('Écriture du dictionnaire...');
blockwrite(f,longueur,1);
for i:=high(s) downto 0 do
begin
blockwrite(f,s[i]^.octet,1);
nombrelong(s[i]^.freq,nombre);
for j:=length(nombre)-1 downto 0 do blockwrite(f,nombre[j],1);
end;
writeln('Recherche du point de départ des données...');
k:=0;
m:=0;
for i:=0 to high(s) do m:=length(fin[s[i]^.octet])*s[i]^.freq+m;
m:=(m-1) mod 8;
blockwrite(f,m,1);
writeln('Écriture des données...');
j:=0;
for i:=0 to taille-1 do
begin
for j:=high(fin[p[i]]) downto 0 do
begin
k:=(fin[p[i]][j])*trunc(power(2,m))+k;
if m=0 then
begin
blockwrite(f,k,1);
k:=0;
m:=7;
end
else m:=m-1;
end;
end;
end;
procedure compter(p:fichier;taille:longword; var l:liste; var longueur:byte);
var i:longword;j:byte;l1:liste;t:tableau;
begin
writeln('Bilan des octets...');
j:=255;
longueur:=0;
for i:=0 to 255 do t[i]:=nil;
for i:=0 to taille-1 do
begin
if t[p[i]]=nil then
begin
longueur:=longueur+1;
new(t[p[i]]);
t[p[i]]^.freq:=0;
t[p[i]]^.octet:=p[i];
t[p[i]]^.gauche:=nil;
t[p[i]]^.droite:=nil;
t[p[i]]^.suiv:=nil;
if p[i]<j then j:=p[i];
end;
t[p[i]]^.freq:=t[p[i]]^.freq+1;
end;
l:=t[j];
l1:=l;
for i:=j+1 to 255 do
begin
if assigned(t[i]) then
begin
l1^.suiv:=t[i];
l1:=t[i];
end;
end;
end;
procedure verification(fin:final);
var i:byte;j:longword;
begin
writeln('Vérification');
for i:=0 to 255 do
begin
if length(fin[i])>0 then
begin
write(i,' ');
for j:=high(fin[i]) downto 0 do write(fin[i][j]);
writeln;
end;
end;
end;
procedure verification2(l:liste);
begin
if l<>nil then
begin
writeln(l^.octet,': ',l^.freq);
verification2(l^.suiv);
end;
end;
function sauver(l:liste):sauvegarde;
var s:sauvegarde;
begin
setlength(s,0);
while l<>nil do
begin
setlength(s,length(s)+1);
s[length(s)-1]:=l;
l:=l^.suiv;
end;
sauver:=s;
end;
begin
writeln('Algorithme de Burrows-Weeler :');
importer(a,taille,chemin);
writeln('Création des décalages...');
tabler(d,a,taille,p);
transformer(p,d,taille,f);
writeln('Algorithme de Move-To-Front...');
taille:=length(f);
coder(f,taille);
writeln('Algorithme de Huffman :');
compter(f,taille,l,longueur);
writeln('Tri préliminaire...');
trier(l);
s:=sauver(l);
writeln('Création de l''arbre-dictionnaire...');
arbre(l,fin);
ecrire(fin,f,taille,s,longueur,chemin);
end.