{

For sources of the used units send an e-mail to:

  cellux@vekoll.saturnus.vein.hu

}

program DeZip64;
{$R-,G-,Q-,D-,L-}
uses LowDos,Video,Glob;

const
  MaxSectorsPerTrack = 21;

type
  TSector = record
    Loaded : boolean;
    Data : array[0..255] of byte;
  end;

  PTrack = ^TTrack;
  TTrack = array[0..MaxSectorsPerTrack-1] of TSector;

  TTable = object
    procedure Draw;
    procedure SetSector(t,s : byte; c : char);
  end;

var
  zfname : string;
  dfname : string;
  ZipFile : TFile;
  D64File : TFile;
  Tracks : array[1..35] of PTrack;
  i,j : word;
  Table : TTable;
  Window : TWindow;

procedure Error(s : string);
var
  w : TWindow;
begin
  w.Init(255,255,Length(s)+4,5,'Error');
  w.Draw;
  w.PutStringAt(2,2,s);
  Glob.ReadKey;
  w.Done;
  Window.Done;
  Halt(1);
end;

procedure Message(s : string);
var
  i : word;
begin
  with Window do
  begin
    for i:=1 to Size.X-2 do PutCharAt(i,Size.Y-1,Frame^.FrameChars[6]);
    PutStringAt(2,Size.Y-1,' '+s+' ');
  end;
end;

function SectorsPerTrack(track : byte) : byte;
begin
  case track of
    1..17 : SectorsPerTrack:=21;
    18..24 : SectorsPerTrack:=19;
    25..30 : SectorsPerTrack:=18;
    31..35 : SectorsPerTrack:=17;
  end;
end;

procedure ProcessZipFile(index : byte);
var
  track,sector : byte;
  packmethod : byte;
  len,sign,count,char : byte;
  i,j : word;
begin
  ZipFile.Open(Chr($30+index)+'!'+zfname, omReadOnly);
  if ZipFile.ErrorCode<>0 then
     Error('Cannot open file '+Chr($30+index)+'!'+zfname);
  if index=1 then ZipFile.Seek(smFromStart,4)
             else ZipFile.Seek(smFromStart,2);
  while not ZipFile.Eof do
  begin
    ZipFile.Read(track,1);
    ZipFile.Read(sector,1);
    packmethod:=(track and $C0);
    track:=(track and $3F);
    if (not track in [1..35]) then Error('Invalid track number');
    if (sector>=SectorsPerTrack(track)) then Error('Invalid sector number');
    Table.SetSector(track,sector,'R');
    Tracks[track]^[sector].Loaded:=True;
    j:=0;
    case packmethod of
      $80,$C0 : begin
                  ZipFile.Read(len,1);
                  ZipFile.Read(sign,1);
                  i:=0;
                  while (i<len) and (j<256) do
                  begin
                    ZipFile.Read(char,1); Inc(i);
                    if char=sign then
                    begin
                      ZipFile.Read(count,1); Inc(i);
                      ZipFile.Read(char,1); Inc(i);
                      while (count>0) and (j<256) do
                      begin
                        Tracks[track]^[sector].Data[j]:=char;
                        Inc(j);
                        Dec(count);
                      end;
                      if count>0 then Error('More than 256 bytes in sector');
                    end
                    else
                    begin
                      Tracks[track]^[sector].Data[j]:=char;
                      Inc(j);
                    end;
                  end;
                if i<len then Error('Extra sector information in packet');
                if j<256 then Error('Less then 256 bytes in sector');
                end;
      $40 : begin
              ZipFile.Read(char,1);
              for j:=0 to 255 do
                Tracks[track]^[sector].Data[j]:=char;
            end;
      $00 : begin
              ZipFile.Read(Tracks[track]^[sector].Data[0],256);
            end;
    end;
  end;
  ZipFile.Close;
end;

procedure Help;
begin
  writeln;
  writeln('ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ [DeZip64] ÄÄÄÄÄÄÄÄÄÄÄÄÄÄ');
  writeln('Converts a ZipCoded disk to a .D64 image');
  writeln;
  writeln('Usage : DEZIP64 [infile [outfile]]     ');
end;


{TTable}

procedure TTable.Draw;
var
  i,j : word;
begin
  for i:=1 to 35 do
    for j:=0 to SectorsPerTrack(i)-1 do
      SetSector(i,j,'ù');
end;

procedure TTable.SetSector(t,s : byte; c : char);
begin
  Window.PutCharAt(t+1,s+1,c);
end;

begin
  if ParamCount=0 then Help else
  begin
    Window.Init(255,255,39,23,'DeZip64');
    zfname:=ParamStr(1);
    if (zfname[2]='!') and (zfname[1] in ['1'..'4']) then
      zfname:=Copy(zfname,3,255);
    if ParamCount=2 then dfname:=ParamStr(2) else dfname:=zfname;
    if Pos('.',dfname)>0 then Delete(dfname,Pos('.',dfname),255);
    dfname:=dfname+'.D64';
    zfname:=UpStr(zfname);
    dfname:=UpStr(dfname);
    D64File.Create(dfname,atNormal);
    if D64File.ErrorCode<>0 then Error('Cant create file '+dfname);
    Window.Draw;
    Table.Draw;
    for i:=1 to 35 do
    begin
      if MaxAvail<SizeOf(TTrack) then Error('Not enough memory.');
      New(Tracks[i]);
      for j:=0 to SectorsPerTrack(i)-1 do Tracks[i]^[j].Loaded:=False;
    end;
    for i:=1 to 4 do
    begin
      Message('Processing image #'+Chr($30+i));
      ProcessZipFile(i);
    end;
    Message('Writing D64 image');
    for i:=1 to 35 do
    begin
      for j:=0 to SectorsPerTrack(i)-1 do
      begin
        if not Tracks[i]^[j].Loaded then Error('Sector not found.');
        Table.SetSector(i,j,'W');
        D64File.Write(Tracks[i]^[j].Data[0],256);
      end;
      Dispose(Tracks[i]);
    end;
    Window.Done;
    D64File.Close;
  end;
end.
