Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Spezielles CRC-16: Übersetzung aus C++ (omg) (https://www.delphipraxis.net/112000-spezielles-crc-16-uebersetzung-aus-c-omg.html)

blackdrake 13. Apr 2008 02:37


Spezielles CRC-16: Übersetzung aus C++ (omg)
 
Hallo.

Ich möchte folgenden Code von C++ nach Delphi übersetzen. Leider habe ich kaum Ahnung von der exakten Funktionsweise dieser Codestelle. Es soll eine spezielle Prüfsumme aus einer Datei gelesen werden. Die Datei kenne ich, die zu erwartende Prüfsumme auch. Ich kann aus dem Originalcode aber nicht mal erkennen, ab wann gelesen wird (was bedeutet z.B. "größer-gleich Leerzeichen"?).

C++:

Code:
unsigned short crc16(unsigned char data, unsigned short poly, unsigned short resl)
// Appends one byte to a runing CRC-16 calculation
{
    int i;
    resl^=(unsigned short)(((unsigned short)data)<<8);
    for(i=8;i>0;--i)
    {
        if(resl&0x8000) resl=(unsigned short)((resl<<1)^poly);
        else           resl=(unsigned short)((resl<<1));
    }
    return (resl);
}

unsigned short file_crc16(char *fnam)
// Calculates the CRC-16 of the ISF file
{
    FILE          *finp;
    unsigned char  crcd;
    unsigned short crcr;

    if((finp=fopen(fnam,"rb"))==NULL) return(0xFFFF);

    crcd='0'; crcr=0xFFFF;
    while((fread(&crcd,1,1,finp)==1)&&(crcd>=' '));
    while((fread(&crcd,1,1,finp)==1)&&(crcd>=' '));
    while(fread(&crcd,1,1,finp)==1) crcr=crc16(crcd, 0x1021, crcr);

    fclose(finp);

    return(crcr);
}
Delphi Versuch (total Fehlerhaft):

Delphi-Quellcode:
function my_crc16(data: char; poly, resl: short): short;
var
  i: integer;
begin
    resl := resl xor (ord(data) shl 8);
    for i := 8 downto 1 do
    begin
        if (resl and $8000) = $8000 then
        begin
          resl := (resl shl 1) xor poly;
        end
        else
        begin
          resl := resl shl 1;
        end;
    end;
    result := resl;
end;

procedure TForm2.Button1Click(Sender: TObject);
var
  erg: integer;
  i: integer;
  tmp: string;
begin
  erg := $FFFF;
  for i := 1 to length(memo1.text) - 1 do
  begin
    tmp := copy(memo1.text, i, 1);
    erg := ord(tmp[1]);
    erg := my_crc16(chr(erg), $1021, erg);
  end;
  showmessage(inttohex(erg, 4));
end;
Ich wäre sehr froh, wenn mir jemand helfen könnte.

Gruß
blackdrake

Namenloser 13. Apr 2008 03:27

Re: Spezielles CRC-16: Übersetzung aus C++ (omg)
 
Hallo.
Ich kenne mich mit der C++-Syntax auch nicht gerade sehr gut aus, aber vielleicht hilft dir ja der Wikipediaartikel. Dort findet sich zwar auch C-Quellcode aber auch noch ein Pseudocode in verständlicher Sprache :zwinker:

Muetze1 13. Apr 2008 16:39

Re: Spezielles CRC-16: Übersetzung aus C++ (omg)
 
Einfach hier im Beitragseditor getippt, also wohl noch ein paar syntaktische Fehler drin. Ansonsten stur übersetzt, samt der manchmal unnötigen Typecasts.
Delphi-Quellcode:
function crc16(const AData: Char; APoly, AResult: word): word;
// Appends one byte to a runing CRC-16 calculation
var
  i: integer;
begin
  AResult := AResult xor word(word(AData) shl 8));

  for i := 1 to 8 do
  begin
    if ( AResult and $8000 ) <> 0 then
      AResult := (AResult shl 1) xor APoly
    else
      AResult := AResult shl 1;    
  end;

  result := AResult;
end;

function file_crc16(const AFilename: string): word;
// Calculates the CRC-16 of the ISF file
var
  lFile: TStream; // finp
  lData: Char;    // crcd
  lCRC: Word;     // crcr
begin
  lCRC := $ffff;
 
  try
    lFile := TFileStream.Create(AFilename, fmOpenRead);
    try
      lData := '0';

      while ( lFile.Read(lData, 1) = 1 ) and ( lData >= ' ' ) do ;
      while ( lFile.Read(lData, 1) = 1 ) and ( lData >= ' ' ) do ;

      while ( lFile.Read(lData, 1) = 1 ) do
        lCRC := crc16(lData, $1021, lCRC);
    finally
      lFile.Free;
    end;
  except
    ; // böse..., aber original hat auch keine Exceptions geworfen...
  end;

  result := lCRC;
end:
/EDIT: Fehler korrigiert

blackdrake 13. Apr 2008 20:19

Re: Spezielles CRC-16: Übersetzung aus C++ (omg)
 
Hallo.

Vielen Dank für die Übersetzung! Ich verstehe die Codestellen jetzt etwas besser.
Auf jeden Fall habe ich jetzt zumindestens herausgefunden, dass die 2 >='' einen Start ab "Initial value" bezweckt.

Leider funktioniert der Code nicht so wie im Original, obwohl es theoretisch gleich sein müsste.
Weißt du, wo das Problem liegen könnte?

Hier eine ISF-Datei

Code:
Automatic save #1
Initial value:   196
Iteration:       1594
Number of digits: 660
2233391095887226489252669400293097928968313993852178183738667668494442
9492212526384486180648256622642810060306066783863577455348324982112153
2715135808841488252902869804477229097398710010629119577823823636994210
4216172688309063196431367011997341372581744233400975666507297914430210
4906519900706600977758820709608947205935274463095556013643625406027389
1590711796777899560809902460840131235188036946665800933324481763731427
0021076313459127091279618161151123907253294177760209360100069046919128
7439796929935178513890764052723512111805228535536862593777696129500193
4622665174708257449461421230482444959667668273817821493904138589288012
820049673518847316886010834312
Die CRC-16 Werte mit abschließendem #13#10:

Original: 59F6
Delphi: DFD4

Die CRC-16 Werte ohne abschließendem #13#10:

Original: 470E
Delphi: 358E

3_of_8 13. Apr 2008 21:08

Re: Spezielles CRC-16: Übersetzung aus C++ (omg)
 
Ich bin mir nicht sicher, wie der CRC-16 da funktioniert, aber du könntest es mit der von mir geschriebenen AdCRC.pas hinbekommen. Probier mal aus, was rauskommt, wen du einfach die beiden LSBs aus dem CRC32, den ich berechne, rauspickst.

(Link: http://andorra.cvs.sourceforge.net/a...C.pas?view=log)

blackdrake 13. Apr 2008 21:32

Re: Spezielles CRC-16: Übersetzung aus C++ (omg)
 
Hallo.

Danke für den Hinweis. Aber hier scheint es sich um einen sehr speziellen CRC zu handeln. (Ich habe die Erfahrung machen müssen, dass es keine Einheitlichen CRC16/32 gibt, siehe ModBus und alternierende Startwerte) Es wird außerdem Zeichen für Zeichen berechnet. Deswegen möchte ich beim Originalcode bleiben.

Gruß
blackdrake

Dezipaitor 13. Apr 2008 22:05

Re: Spezielles CRC-16: Übersetzung aus C++ (omg)
 
Du kannst auch einfach den C Code in eine OBJ Datei kompilieren und dann diese in Delphi einbinden. Dann musst du nur noch die Funktionsköpfe nach Delphi konvertieren.

Rudy hat einen Artikel darüber geschrieben: http://rvelthuis.de/articles/articles-cobjs.html

Muetze1 14. Apr 2008 00:29

Re: Spezielles CRC-16: Übersetzung aus C++ (omg)
 
Ich habe bei dem Code zuvor eigenmächtig eine Optimierung gemacht, die aber zu einem falschen Ergebnis führt. Von daher habe ich oben den Code korrigiert. Bitte den Code erneut ausprobieren.

gammatester 14. Apr 2008 10:49

Re: Spezielles CRC-16: Übersetzung aus C++ (omg)
 
Das CRC-Polynom ist das altbekannte CRC-16-CCITT (Dein Code benutzt den Startwert $FFFF statt wie meist $0000); das bedeutet auch, daß 3_of_8's Hinweis nicht zum Erfolg führen wird.

Ich weiß zwar nicht, was ISF-Files sind (http://filext.com/file-extension/ISF listet einige), aber der C++ Code öffnet sie binär.

Allerdings scheint mit der Code nicht sehr sinnvoll, da erstmal zwei Blöcke mit Zeichen >= ' ' überlesen werden. Wenn man die Beispieldatei wörtlich nimmt, würden also Automatic save #1 und Initial value: 196 überlesen und die CRC-Berechnung startet mit dem #13#10 danach.

Also: erstmal klären worüber genau der CRC berechnet werden soll.

Gruß Gammatester

Muetze1 14. Apr 2008 10:52

Re: Spezielles CRC-16: Übersetzung aus C++ (omg)
 
Zitat:

Zitat von gammatester
Allerdings scheint mit der Code nicht sehr sinnvoll, da erstmal zwei Blöcke mit Zeichen >= ' ' überlesen werden. Wenn man die Beispieldatei wörtlich nimmt, würden also Automatic save #1 und Initial value: 196 überlesen und die CRC-Berechnung startet mit dem #13#10 danach.

Nein, "Initial value" wird schon mit einberechnet, da "Automatic save #1" schon zwei Leerzeichen hat. Er fängt also die CRC Berechnung mit dem "#" von "#1" an.

gammatester 14. Apr 2008 12:00

Re: Spezielles CRC-16: Übersetzung aus C++ (omg)
 
Zitat:

Zitat von Muetze1
Zitat:

Zitat von gammatester
Allerdings scheint mit der Code nicht sehr sinnvoll, da erstmal zwei Blöcke mit Zeichen >= ' ' überlesen werden. Wenn man die Beispieldatei wörtlich nimmt, würden also Automatic save #1 und Initial value: 196 überlesen und die CRC-Berechnung startet mit dem #13#10 danach.

Nein, "Initial value" wird schon mit einberechnet, da "Automatic save #1" schon zwei Leerzeichen hat. Er fängt also die CRC Berechnung mit dem "#" von "#1" an.

Das seh ich anders: Die erste while-Schleife verwirft alles bis 'Automatic save #1'#13 und endet weil #13<' ', die zweite while-Schleife liest #10 und endet. Also müßte doch mit 'Initial value: 19'#13#10 begonnen werden (anders als in meinem ersten Beitrag).

Gruß Gammatester

Muetze1 14. Apr 2008 12:04

Re: Spezielles CRC-16: Übersetzung aus C++ (omg)
 
Zitat:

Zitat von gammatester
Das seh ich anders: Die erste while-Schleife verwirft alles bis 'Automatic save #1'#13 und endet weil #13<' ', die zweite while-Schleife liest #10 und endet. Also müßte doch mit 'Initial value: 19'#13#10 begonnen werden (anders als in meinem ersten Beitrag).

Ja, das ist richtig. Ich hatte vorhin auch ein Denkfehler von wegen >= ' ' und > ' '. Aber deine letzte Aussage ist nun korrekt, die unterschreibe ich so mit...

blackdrake 14. Apr 2008 13:33

Re: Spezielles CRC-16: Übersetzung aus C++ (omg)
 
Hallo.

Vielen Dank für eure Hilfe. Ihr habt mir sehr geholfen! :-D

Zitat:

Zitat von Muetze1
Ich habe bei dem Code zuvor eigenmächtig eine Optimierung gemacht, die aber zu einem falschen Ergebnis führt. Von daher habe ich oben den Code korrigiert. Bitte den Code erneut ausprobieren.

Deine Veränderung hatte ich bei dem Codevergleich C/Delphi zwar bemerkt, aber ich hatte ebenfalls nicht erkannt, dass durch die Ausklammerung des "AResult SHL 1" die If-Abfrage beeinflusst wird. Mit dem korrigierten Code wird nun die Prüfsumme korrekt wie im Originalprogramm berechnet.

Zitat:

Zitat von gammatester
Das CRC-Polynom ist das altbekannte CRC-16-CCITT (Dein Code benutzt den Startwert $FFFF statt wie meist $0000);

Gut, zu wissen, wie der Algorithmustyp genau heißt. Danke für den Hinweis. Trotzdem scheint mir die Funktion ein Exot zu sein, da der Programmierer auch irgendetwas mit dem Wert $1021 (als "Poly") macht :?

Zitat:

Zitat von Muetze1
Nein, "Initial value" wird schon mit einberechnet, da "Automatic save #1" schon zwei Leerzeichen hat. Er fängt also die CRC Berechnung mit dem "#" von "#1" an.

Ich verstehe dieses ganze mit dem >= '' nicht wirklich. Es werden scheinbar die ASCII-Werte des Chars verglichen. Ich konnte aber wie gesagt mit dem Delphi-Code durch showmessage(lData); innerhalb der While-Schleife nachweisen, dass der CRC tatsächlich mit "Initial value" beginnt. Das ist auch absolut korrekt so, da die erste Zeile der Dateikopf ist und nach dem # die CRC-Summe als Dezimal stehen muss.

Der originale C-Code mit dem >= '' erscheint mir irgendwie etwas unprofessionell. Hätte man besser lösen können. Es ist für dritte Personen ohne Debugging-Tools unklar zu erkennen. Jetzt, wo ich die Prüfsummen jedoch korrekt berechnen kann, kann ich die Funktionen für Stringeingaben anstelle von Dateieingaben anpassen.

Gruß
blackdrake

gammatester 14. Apr 2008 14:53

Re: Spezielles CRC-16: Übersetzung aus C++ (omg)
 
Zitat:

Zitat von blackdrake
Gut, zu wissen, wie der Algorithmustyp genau heißt. Danke für den Hinweis. Trotzdem scheint mir die Funktion ein Exot zu sein, da der Programmierer auch irgendetwas mit dem Wert $1021 (als "Poly") macht :?

Was da "gemacht" wird ist folgendes: Ein Zeichen wird bitweise durch den Algorithmus gedreht und wenn's ein Carry gibt, wird das Polynom "subtrahiert" (= xor). Normalerweise berechnet man die CRCs mit Hilfe von Tabellen (je ein Eintrag für ein Byte), hier

Delphi-Quellcode:
  ctab: array [0..255] of word =
          ( $0000, $1021, $2042, $3063, $4084, $50A5, $60C6 ...
Der CRC-Code ist kein Exot, sondern das worüber der CRC berechnet wird. Gibt es eigentlich einen Link oder so auf den Original-C++-Code?

Gruß Gammatester

blackdrake 14. Apr 2008 15:27

Re: Spezielles CRC-16: Übersetzung aus C++ (omg)
 
Hallo. Ja, der Code stammt von http://users.tmok.com/~pla/lychrel/lychrel.shtml (isft2757.zip). Ein Utility mit dem man ISF-Dateien auf Validität prüft. (= Inoffizieller Standard für Computingsoftware, die Lychrel Zahlen lösen soll)

gammatester 14. Apr 2008 20:20

Re: Spezielles CRC-16: Übersetzung aus C++ (omg)
 
Zitat:

Zitat von blackdrake
Hallo. Ja, der Code stammt von http://users.tmok.com/~pla/lychrel/lychrel.shtml (isft2757.zip). Ein Utility mit dem man ISF-Dateien auf Validität prüft. (= Inoffizieller Standard für Computingsoftware, die Lychrel Zahlen lösen soll)

Ich hab das Teil mal gesaugt und auf Dein ISF losgelassen. Für das Original gibt es eine Fehlermeldung (CRC im File sei 1). Wenn man den Code von Muetze1 laufen läßt, ergibt sich ein CRC von 23030, trägt man diesen Wert in Zeile 1 ein, dann meldet ISFTool "File has correct CRC-16, 59F6". Hinweis: 23030 = $59F6.

Automatic save #23030
Initial value: 196
Iteration: 1594
Number of digits: 660
22333910958872264892526694002930979289683139938521 78183738667668494442
94922125263844861806482566226428100603060667838635 77455348324982112153
27151358088414882529028698044772290973987100106291 19577823823636994210
42161726883090631964313670119973413725817442334009 75666507297914430210
49065199007066009777588207096089472059352744630955 56013643625406027389
15907117967778995608099024608401312351880369466658 00933324481763731427
00210763134591270912796181611511239072532941777602 09360100069046919128
74397969299351785138907640527235121118052285355368 62593777696129500193
46226651747082574494614212304824449596676682738178 21493904138589288012
820049673518847316886010834312


Zu beachten ist, daß ISFTool den CRC in dezimal ab Spalte 17 erwartet.

Gruß Gammatester

blackdrake 14. Apr 2008 20:24

Re: Spezielles CRC-16: Übersetzung aus C++ (omg)
 
Zitat:

Zitat von gammatester
Zu beachten ist, daß ISFTool den CRC in dezimal ab Spalte 17 erwartet.

Hallo.

Mit dem CRC-16-Test bin ich schon komplett durch. Das mit der 17ten Stelle weiß ich auch. Ich hatte in der originalen Datei den CRC-Wert 1 gesetzt, weil mein Programm, das die ISF geschrieben hat, zu diesem Zeitpunkt nicht ISF-Konform war. Jetzt habe ich ja den korrekten Algorithmus und kann daher Dateien valid lesen und schreiben.

Gruß
blackdrake


Alle Zeitangaben in WEZ +1. Es ist jetzt 05:26 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz