(*
*******************************************************************************
*         Copyright (C) SofCon 2002 All Rights Reserved                       *
*******************************************************************************
*
*    project:     vizualizace
*
*    title:       File2.pas
*
*******************************************************************************
*
*    description: priklad podpory pro dva soubory vetsi nez paket
*
*    version:     1.02
*    language:    Borland Pascal
*
*    author:      Hvozdovic
*    history:     date      sign   remark
*                 8.02      hv     zacatek vyvoje
*                11.02      hv     prvni release
*                11.02      hv     zruseni odkazu na ChnPrt, ChnSofs2
*                                  kontrola alokace pameti(NIL) +
*                                       doplneno uvolnovani pameti +
*                                   oprava volani ExLockKernel
*****************************************************************************
*)
{$I sets.inc}

unit File2;
interface
uses
   Objects              { objekty }
  ,ChnVirt              { virtualni kanal }
  ,ChnSofT              { definice typu pro protokol SofCon }
  ,Xtking_1             { definice typu a konstant pro praci s vizualizaci }
  ,NumToStr             { prace s retezci }
  ,WTVirt               { virtualni predek vsech vizualizacnich objektu }
  ,WTFile;              { objekt s podporou prenosu souboru }


const
  { max. velikost binarnich souboru }
  cBinSize = 4000;

type
 { vyctovy typ popisujici banky souboru }
  tFileEnum =
  (
    file_Bin,      {binarni soubor 1}
    file_Bin1      {binarni soubor 2}
  );


  { objekt pracujici s soubory }
  PFile2 = ^TFile2;
  TFile2 = object(TWinTickFile)
    constructor Init;
    destructor Done; virtual;

    function   fnGetFileCnt:Byte; virtual;

    procedure  fnAbort; virtual;
    function   fnClose:Byte; virtual;
    procedure  fnGetBankListItem(var FileBankListItem:TFileDataHeader); virtual;
    function   fnGetBankDataOpen(var FileBankDataInfo:TFileBankDataInfo):Byte; virtual;
    function   fnGetBankDataBlock(var FileBankDataBlock:TDataBlockFile):Byte; virtual;
    function   fnPutBankDataOpen(var FileBankDataOpen :TPutFileBankDataOpen):Byte; virtual;
    function   fnPutBankDataBlock(var FileBankDataBlock:TDataBlockFile):Byte; virtual;
  end;


var
  { synchronizacni flag }
  fFileBankIsUsed:Boolean;
  { deskriptory bank souboru }
  pFileDescArray : array[tFileEnum] of ^TFileDataHeader;
  pBin, pBin1 : Pointer;


{ procedura pro zobrazeni stavu - zobrazi se stiskem klavesy "1" }
procedure ShowState;

{ inicializuje pole struktur popisujicich jednotlive banky souboru
  a uzivatelska data}
procedure InitBankDescUserData;


implementation
uses
  Kernel;

{ inicializuje pole struktur popisujicich jednotlive banky souboru
  a uzivatelska data}
procedure InitBankDescUserData;
var
  w:Word;
begin
  { inicializace bank souboru a uzivatelskych dat }
  { alokace pameti pro binarni pole }
  GetMem(pBin, cBinSize);
  if pBin=nil then RunError(255);
  GetMem(pBin1, cBinSize);
  if pBin1=nil then RunError(255);

  { inicializace popisu banky #1 }
  New(pFileDescArray[file_Bin]);
  if pFileDescArray[file_Bin]=nil then RunError(255);
  with pFileDescArray[file_Bin]^ do
  begin
    NextHeaderFl := file_Bin<High(tFileEnum);  { priznak ne-posledniho prenaseneho header    }
    FileBankNum  := byte(file_Bin);            { cislo banky souboru - zakladni adresa banky }
    FileBankName := 'BIN file';                { jmeno banky / jmeno typu banky / urceni banky }
    FileName     := 'Bin.bin';                 { jmeno souboru zavedeneho do banky }
    FileSize     := cBinSize;                  { velikost souboru v bance }
    FileDaTi     := GetPackTime;               { datum a cas souboru DOS packed-format }
    FileAttr     := 0;                         { atributy souboru dle Delphi kodovani  }
  end;
  { inicializace popisu banky #2 }
  New(pFileDescArray[file_Bin1]);
  if pFileDescArray[file_Bin1]=nil then RunError(255);
  with pFileDescArray[file_Bin1]^ do
  begin
    NextHeaderFl := file_Bin1<High(tFileEnum); { priznak ne-posledniho prenaseneho header    }
    FileBankNum  := byte(file_Bin1);           { cislo banky souboru - zakladni adresa banky }
    FileBankName := 'BIN file1';               { jmeno banky / jmeno typu banky / urceni banky }
    FileName     := 'Bin1.bin';                { jmeno souboru zavedeneho do banky }
    FileSize     := cBinSize;                  { velikost souboru v bance }
    FileDaTi     := GetPackTime;               { datum a cas souboru DOS packed-format }
    FileAttr     := 0;                         { atributy souboru dle Delphi kodovani  }
  end;

 {$ifdef Deb_crt}
  writeln('nastaveni nahodnych cisel');
 {$endif}
  RandSeed:=1013;
  for w:=0 to cBinSize-1 do
  begin
    PByteArray(pBin)^[w]:=Random(256);
    PByteArray(pBin1)^[w]:=Random(256);
  end;
end;

{ uvolnuje pole struktur popisujicich jednotlive banky souboru
  a uzivatelska data }
procedure DoneBankDescUserData;
begin
  { uvolneni bank souboru a uzivatelskych dat }
  FreeMem(pBin, cBinSize);
  FreeMem(pBin1, cBinSize);

  { uvoleni popisu banky #1 }
  Dispose(pFileDescArray[file_Bin]);
  { uvolneni popisu banky #2 }
  Dispose(pFileDescArray[file_Bin1]);
end;

{ procedura pro zobrazeni stavu - zobrazi se stiskem klavesy "1" }
procedure ShowState;
var
  w:Word;
  fLock:Boolean;
begin
  if fFileBankIsUsed then
  begin
    Writeln('Banky souboru jsou pouzivany, proto nelze zobrazit jejich stav');
    exit;
  end;

  { synchronizace promennych - zamknuti jadra proti prepnuti
    procesu.
    Tato synchronizace je dostatecna pokud k promennym pristupuji
    ruzne procesy. V pripade pristupu k promennym z prerusovaci
    obsluhy by zde musela byt pouzito zakazani preruseni (pushf cli) }
  fLock:=ExLockKernel;
   writeln('Vypis prvnich nekolika cisel');
   writeln('Bin:');
   for w:=0 to 40 do write(PByteArray(pBin)^[w], ',');
   writeln;

   writeln('Bin1:');
   for w:=0 to 40 do write(PByteArray(pBin1)^[w], ',');
   writeln;
  { synchronizace promennych - odemknuti jadra, viz. vyse }
  if not fLock then UnLockKernel;
end;


constructor TFile2.Init;
var
  w:Word;
begin
  inherited Init;

  { inicializace popisovacu bank souboru a uzivatelskych dat }
  InitBankDescUserData;
end;

destructor TFile2.Done;
begin
  { uvolneni popisovacu bank soubour }
  DoneBankDescUserData;

  inherited Done;
end;


function   TFile2.fnGetFileCnt:Byte;
begin
  { vraci pocet bank souboru }
  fnGetFileCnt:=Byte(High(tFileEnum))+1;
end;

procedure  TFile2.fnAbort;
begin
  { zruseni prace s banky souboru }
  fFileBankIsUsed:=False;
end;

function  TFile2.fnClose:Byte;
begin
  { ukonceni prace s banky souboru }
  fFileBankIsUsed:=False;
  fnClose:=erc_file_OK;
end;


procedure  TFile2.fnGetBankListItem(var FileBankListItem:TFileDataHeader);
begin
  { nastaveni headeru popisujiciho pozadovanou banku souboru m_bFile
    Tato funkce slouzi pro ziskani informaci o jednotlivych bankach
    pri jejich zobrazeni ve vizualizaci. }
  FileBankListItem:=pFileDescArray[tFileEnum(m_bFile)]^;
  FileBankListItem.FileDaTi:=GetPackTime;
end;

function  TFile2.fnGetBankDataOpen(var FileBankDataInfo:TFileBankDataInfo):Byte;
begin
  { nastaveni headeru popisujici pozadovanou banku souboru m_bFile.
    Tato funkce se vola pred otevrenim banky pro cteni dat a odrazi
    aktualni stav banky souboru. Stavem banky se predevsim mysli
    aktualni velikost souboru.
    Pozn. v prikladech byly kvuli jednoduchosti pouzity soubory
          s pevnou delkou.
    Pozn. predek provede konverzi indexu banky podle predaneho oznaceni
          banku a nastavi promennou m_bFile }
  fnGetBankDataOpen:=erc_file_Ok;
  FileBankDataInfo:=pFileDescArray[tFileEnum(m_bFile)]^;
  FileBankDataInfo.FileDaTi:=GetPackTime;

  { zde by mel byt kod, ktery aplikaci zabrani v pristupu
    k vybrane bance souboru.
    Pokud by zde kod nebyl mohlo by dojit k rozsynchronizovani
    jednotlivych dat.}
  fFileBankIsUsed:=True;
end;

function  TFile2.fnGetBankDataBlock(var FileBankDataBlock:TDataBlockFile):Byte;
begin
  fnGetBankDataBlock:=erc_file_Ok;
  { vypocet kolik dat lze prenest v jednom datovem paketu
    a nastaveni priznaku prenosu dat ve vice paketech }
  FileBankDataBlock.DataFileOffs:=m_liFileOffs;
  if m_liFileOffs+SizeOf(TBinBlockFile)<=cBinSize then
  begin
    FileBankDataBlock.NextBlockFl:=True;
    FileBankDataBlock.BlockSize:= SizeOf(TBinBlockFile);
  end
  else
  begin
    FileBankDataBlock.NextBlockFl:=False;
    FileBankDataBlock.BlockSize:= cBinSize-m_liFileOffs;
  end;

  { nastaveni datoveho bufferu dle stavu komunikace a vybraneho banku
    souboru m_bFile }
  case tFileEnum(m_bFile) of
  file_Bin:  Move(PByteArray(pBin)^[m_liFileOffs], FileBankDataBlock.Block,
                             FileBankDataBlock.BlockSize);

  file_Bin1: Move(PByteArray(pBin1)^[m_liFileOffs], FileBankDataBlock.Block,
                             FileBankDataBlock.BlockSize);
  end;
  Inc(m_liFileOffs, FileBankDataBlock.BlockSize);
end;

function   TFile2.fnPutBankDataOpen(var FileBankDataOpen :TPutFileBankDataOpen):Byte;
begin
  { Funkce se vola pred zapisem binarnich dat do pozadovaneho banku
    souboru. Ve vetsine pripadu zde postaci provest kontrolu, jestli
    zapisovana data lze do vybrane banky zapsat
    Pozn. predek provede konverzi indexu banky podle predaneho oznaceni
          banku a nastavi promennou m_bFile }
  fnPutBankDataOpen:=erc_file_Ok;
  if FileBankDataOpen.FileSize > cBinSize then fnPutBankDataOpen:=erc_file_InsufficientMemory;;

  { zde by mel byt kod, ktery aplikaci zabrani v pristupu
    k vybrane bance souboru.
    Pokud by zde kod nebyl mohlo by dojit k rozsynchronizovani
    jednotlivych dat.
    Pro zjednoduseni prikladu je pouzit flag zabranujici praci se vsemi
    banky. }
  fFileBankIsUsed:=True;
end;

function  TFile2.fnPutBankDataBlock(var FileBankDataBlock:TDataBlockFile):Byte;
begin
  fnPutBankDataBlock:=erc_file_Ok;
  with FileBankDataBlock do
  begin
    { nastaveni hodnot vybraneho banku souboru m_bFile podle stavu komunikace
      z datoveho bufferu ve strukture FileBankDataBlock }
    case tFileEnum(m_bFile) of
    file_Bin:  Move(Block, PByteArray(pBin)^[m_liFileOffs], BlockSize);

    file_Bin1: Move(Block, PByteArray(pBin1)^[m_liFileOffs], BlockSize);
    end;

   {$ifdef Deb}
    if DataFileOffs<>m_liFileOffs then RunError(255);
   {$endif}

    Inc(m_liFileOffs, BlockSize);
    if not NextBlockFl then
    begin
      pFileDescArray[tFileEnum(m_bFile)]^.FileSize:=m_liFileOffs;
    end;
  end;
end;

end.