Suma Kontrolna CRC32

0

Witam wszystkich,

ja mam pytanie odnośnie zamieszczonego na łamach serwisu 4programmers.net tego artykułu:

http://4programmers.net/Delphi/FAQ/Jak_wylicza%C4%87_sum%C4%99_kontroln%C4%85_CRC-32_(kontrola_b%C5%82%C4%99d%C3%B3w)
Co prawda, stary to artykuł, ale temat wciąż jest na topie. Pytanie kieruję do osób, które znają się na rzeczy.

Proszę mi wytłumaczyć, w jaki sposób mam zliczyć sumę kontrolną pliku z dowolnymi danymi, tak, żeby wynik CRC został zapisany w tym samym pliku, a po ponownym odczycie tych danych, program mógł sprawdzić, czy obliczona bieżąca suma kontrolna CRC zgadza się z tą zapisaną w pliku. Bo problem w tym, że zapis wyniku CRC, też wpływa na zmianę całej sumy kontrolnej CRC pliku.
I jeszcze jedno pytanie: Czy to normalne, że nieraz wynikiem sumy kontrolnej jest liczba ujemna?

Pozdrawiam i z góry dziękuję za wskazówki
RYGAR

0

Teoretycznie jesli wynik CRC32 dopisze sie na koncu pliku (wczesniej liczac crc z dopisanymi zerami - tu dla 32 bitowego crc) to latwo mozna go odseparowac, mozna tez policzyc CRC z calosci i powinno ono dac zero.

0
reichel napisał(a)

...mozna tez policzyc CRC z calosci i powinno ono dac zero.

A czy mógłbyś oprzeć się na jakimś przykładzie i pokazać, w skrócie, jak to zrobić? Jestem dopiero początkujący i nie bardzo wiem jak mam się do tego zabrać. Oczywiście, chciałbym, aby przykład był oparty na programie, do którego link wcześniej podałem.

Za dobre chęci z góry dziękuję...

Pozdrawiam
RYGAR

0

to co moge na szybko

var    Plik     :File;
       Buf     : array[1..1024*10]of byte;
       BufC     : array[1..4]of byte;
       Res, x : Longint;
       CRC   : Longint	;

begin
 CRC := CRCSEED;
 AssignFile(Plik, 'Dane.dat'); //było: Assign
 Reset(Plik, 1);


 Repeat
  BlockRead(Plik, Buf, SizeOf(Buf), Res);
  For x:=1 to Res do
   CRC:=CRC32(Buf[x], CRC);
 Until Res<>SizeOf(Buf);


  WriteLn(FOrmat('%x',[Crc]));


 CloseFile(Plik);  //było: Close

//zapisz crc - mozna do pliku, tu aby pokazac
CopyMemory(@BufC,@CRC,4);

 CRC := CRCSEED;
 AssignFile(Plik, 'Dane.dat'); //było: Assign
 Reset(Plik, 1);
 Repeat
  BlockRead(Plik, Buf, SizeOf(Buf), Res);
  For x:=1 to Res do
   CRC:=CRC32(Buf[x], CRC);
 Until Res<>SizeOf(Buf);

//dodaj sume crc (mozna dokleic do pliku)
  For x:=1 to 4 do
  begin
   CRC:=CRC32(BufC[x], CRC);
  end;


 CloseFile(Plik);  //było: Close

//powinna byc zero 
 WriteLn(FOrmat('%x',[Crc]));

end;

chyba powinno dzialac ....

0

No więc, troszkę z CRC się pomęczyłem, ale o dziwo udało mi się osiągnąć zamierzony rezultat ;]

Po pierwsze - miałem problem z instrukcją: WriteLn(FOrmat('%x',[Crc])), która w Delphi nie działała. O ile pamiętam, to chyba taka instrukcja była stosowana w Turbo Pascal'u pod DOS'em.
Druga sprawa - to że nie bardzo wiem czemu ma służyć fragment programu:
For x:=1 to 4 do
begin
CRC:=CRC32(BufC[x], CRC);
end;
Po wyłączeniu tego kodu wszystko i tak działa jak należy.

W zasadzie cała modyfikacja programu sprowadzała się do użycia instrukcji zapisującej CRC w pliku: BlockWrite.

Jednej rzeczy tylko pojąć nie mogę z tym CRC. Przykładowo: mam plik z danymi, który zawiera 100 Bajtów. Najpierw program oblicza CRC (z tych 100 Bajtów). Następnie wynik CRC jest zapisywany ponownie w pliku z danymi, a więc plik rośnie do 104 Bajtów (CRC = Longint). Kolejna procedura odczytuje dane z pliku (a więc tym razem 104 Bajty), wylicza z nich CRC - (i tu mnie właśnie zaskakuje) - zwraca w wyniku CRC=0. (?) Dziwne to dla mnie, bo przecież zapisany CRC, to wynik obliczony ze 100, a nie ze 104 Bajtów ? Jak to możliwe, że pomimo tego wszystko działa prawidłowo ?

Za wszelki wskazówki i pomoc dziękuję...

Mam jeszcze jedno pytanie. Jak ustawić wskaźnik pliku na koniec danych? Bo wiem, że w Turbo Pascalu była chyba instrukcja Append, czy jakoś tak... a w Delphi jak to zrobić?
Z punktu assemblera też nie ma z tym problemu, bo można plik otworzyć do odczytu, do zapisywania i właśnie do dopisywania danych...

Pozdrawiam
RYGAR

A oto zmiany jakich dokonałem w programie. Dodałem dwa Buttony. Do jednego przypisałem zdarzenie, które ma za zadanie dopisać CRC w pliku. Po kliknięciu drugiego Buttonu, program odczytuje dane z pliku, oblicza CRC i zwraca wynik w polu Edit.

//Programu CRC (fragment)


const
    CRCSEED = $FFFFFFFF;

var    Plik   : File;
       Buf    : array[1..1024*10]of byte;
//       BufC   : array[1..4]of byte;
       Res, x : Longint;
       CRC    : Longint;


function CRC32(Value: Byte; Crc: Longint) : Longint;
begin
  Result := CRC32TAB[BYTE(CRC XOR LONGINT(VALUE))] XOR
           ((CRC SHR 8) AND $00FFFFFF);
 //CRC32TAB - tablica zadeklarowana i wspomniana wcześniej
end;

// odczyt danych i sprawdzenie CRC
procedure TForm1.Button1Click(Sender: TObject);
begin
 CRC := CRCSEED;
 AssignFile(Plik, 'Dane.txt'); //było: Assign
 Reset(Plik, 1);
 Repeat
  BlockRead(Plik, Buf, SizeOf(Buf), Res);
  For x:=1 to Res do
   CRC:=CRC32(Buf[x], CRC);
 Until Res<>SizeOf(Buf);

//dodaj sume crc (mozna dokleic do pliku)

{  For x:=1 to 4 do
  begin
   CRC:=CRC32(BufC[x], CRC);
  end; }


 CloseFile(Plik);  //było: Close

//powinna byc zero
// WriteLn(FOrmat('%x',[Crc]));
 Edit1.Text := IntToStr(CRC);

end;

// zapis CRC na końcu pliku
procedure TForm1.Button2Click(Sender: TObject);
begin
 CRC := CRCSEED;
 AssignFile(Plik, 'Dane.txt'); //było: Assign
 Reset(Plik, 1);

 Repeat
  BlockRead(Plik, Buf, SizeOf(Buf), Res);
  For x:=1 to Res do
   CRC:=CRC32(Buf[x], CRC);
 Until Res<>SizeOf(Buf);

//  WriteLn(F0rmat('%x',[Crc]));
    Edit1.Text := IntToStr(CRC);

 BlockWrite(Plik, CRC, 4); //zapisujemy na końcu pliku CRC

 CloseFile(Plik);  //było: Close

//zapisz crc - mozna do pliku, tu aby pokazac
//CopyMemory(@BufC,@CRC,4);

end;

end.
0
  1. Petla byla aby pokazac o co chodzi .... nie modyfikowalem pliku (i napisale, ze mozna pominac).

  2. co do WriteLn(FOrmat('%x',[Crc])) dziala w delphi ale trzeba dodac {$APPTYPE CONSOLE}, gdziekolwiek.

  3. plik i jego koniec seek, filesize

  4. HELP !!!!!! F1 !!!

0

Bardzo dziękuję Rygar-owi za piękny wpis na forum i działajacy pieknie program !

1 użytkowników online, w tym zalogowanych: 0, gości: 1