james beckmann: foxpro crc32 routine nach php

he!

für einen shop ist es nötig, checksummen zu berechnen. diese werte kommen allerdings von foxpro,
     die allerdings dem ergebnis von crc32() unter php garnicht ähnlich sind. also hat der foxpro
     programmierer eine foxpro-routine für crc32 aus dem internet inkl. quelltext gefischt, welche
     ich nun in php umgesetzt habe. leider bekommen wir auch hier völlig andere ergebnisse.
     hier der haupteil in foxpro:

Init-Methode:
     *------ inicialization This.CRCTbl -----------------------*
     This.CRCTbl(001) = 0x00000000
     ...
     This.CRCTbl(256) = 0x2d02ef8d

Methode: STRCRC32

lParameters tcStr
     Local lnCrc32, ix, lnZ, lnByte
     If Empty(tcStr)
       Return 0 &&Space(8)
     Else
       lnCrc32 = 0xFFFFFFFF
       For iX = 1 To Len(tcStr)
         lnByte = Asc(SubStr(tcStr, iX, 1))
         lnZ = BitXor(lnByte, BitAnd(lnCrc32, 0x000000FF))
         lnCrc32 = BitXor(This.CRCTbl(lnZ + 1), BitRShift(lnCrc32, 8))
       EndFor
       lnCrc32 = BitNot(lnCrc32)
       If lnCRC32 < 0
         lnCRC32 = Int(lnCRC32 + 0x100000000)
       EndIf
     *  Return This.DecToHex(lnCrc32)
       Return (lnCrc32)
     EndIf

hier in php:

function STRCRC32($tcStr)
     {
       $CRCTbl[001] = 0x00000000;
                 ...
       $CRCTbl[256] = 0x2d02ef8d;

$lnCrc32 = 0xFFFFFFFF;

For ($iX=0; $iX<strlen($tcStr); $iX++)
       {
         $lnByte = ord(SubStr($tcStr, $iX, 1));
         $lnZ = $lnByte ^ ($lnCrc32 & 0x000000FF);
         $lnCrc32 = $CRCTbl[$lnZ + 1] ^ ($lnCrc32 >> 8);
       }

$lnCrc32 = ~$lnCrc32;

If ($lnCRC32 < 0) $lnCRC32 = Intval($lnCRC32 +                          0x100000000);

Return $lnCrc32;

}

echo STRCRC32("A");

irgendetwas läuft da schief. vieleicht kennt sich ja jemand von euch damit aus.

gruss
     j.b.

  1. Hi James!

    [...]  If ($lnCRC32 < 0) $lnCRC32 = Intval($lnCRC32 + 0x100000000);

    Das macht Probleme. PHP behandelt Integer als vorzeichenbehaftet und klippt bei der Konvertierung auf die Grenzen. Eventuell erfolgt auch eine Typkonvertierung in Float - da geht dann auch mehr.
    Für ne Lösung kann der Rückgabewert kein Integer mehr sein:

    if($lnCRC32 < 0) $lnCRC32 = 4294967296+ $lnCRC32;

    sollte gehen, da 4294967296 gleich als Float angelegt wird.

    Gruss,
     Carsten

    1. if($lnCRC32 < 0) $lnCRC32 = 4294967296+ $lnCRC32;

      sollte gehen, da 4294967296 gleich als Float angelegt wird.

      hi,

      hmm. das ging leider auch nicht. dummerweise habe ich kein foxpro um mal
      zeile für zeile zudebuggen. aber ich denke auch das es bei der typenkonvertierung
      zu problemen kommt. mal schauen, irgendwo eine alte version gefunden. müßte doch
      vb kompatibel sein ...

      gruss

      j.b.

      1. Hallo james!

        Ich hab sowas auch mal von Assembler nach C nach PHP 'portiert', und hatte dabei mit den Typen Probleme (Die Integer in PHP sind prinzipiell vorzeichenbehaftet). Nur habe ich den Code nicht hier und kann mich nicht genau erinnern - wenns bis Montag Zeit hat ...

        Einen hab ich allerdings noch, statt:
          $lnCrc32 = 0xFFFFFFFF;  // <-- das ist ein Float, der bei der ersten bitoperation zerlegt wird!
        mal so:
          $lnCrc32 = -1;
        probieren.

        Ausserdem müsstest du in CRCTbl alle Zahlen grösser 0x7fffffff durch ihre vorzeichenbehaftete Darstellung ersetzen.

        (also jeweils $JetzigerWert-4294967296, statt dem bisherigen Eintragen, wenn es denn negativ ist.)

        Gruss,
         Carsten

        1. hi,

          super dank ersteinmal. hat aber alles nichts geholfen.
          leider konnte ich auch keine alte foxpro version auffinden.
          evt. werde ich dann diese woche zum entwickler der software
          hin und mit ihm das problem durchgehen. obwohl dieser recht
          komplexe anwendungen schreibt, stehen wir beide trotzdem
          jedesmal wie ochs vorm berg wenn es um bit-operationen und
          verschiebungen geht. aus meiner assemblerzeit mitte der 80´er
          ist leider einiges auf der strecke geblieben. ich weiß, so
          schwer ist das eigentlich garnicht, aber wir haben keine
          zeit das problem zulösen und überlegen eine eigene sache
          zuentwicklen. mal sehen. die überlegen jetzt den datenabgleich
          per email zubewerkstelligen. evt. fällt mir da dann sowieso eine
          andere möglichkeit ein.

          gruss,
          j.b.

          evt. finde ich mal den source der php crc32 routine ...

          1. Hallo james!

            Diese Zeile kann noch ärger machen:

            $lnCrc32 = $CRCTbl[$lnZ + 1] ^ ($lnCrc32 >> 8);

            wenn nämlich von links das Vorzeichen nachrückt (wie es für vorzeichenbehaftete Zahlen richtig wäre)
            dann sollte
             (($lnCrc32 >> 8)&0x00ffffff)
            das korrigieren.

            Gruss,
             Carsten

            1. hallo,

              deinen letzten vorschlagt ebenfalls beherzt - mit dem erfolg das die zahlen
              zumindet jetzt durchweg im ergebnis positiv sind und die anzahl der stellen
              gleich ist. die routine sieht jetzt so aus:

              ...

              $lnCrc32 = -1;

              For ($iX=0; $iX<strlen($tcStr); $iX++)
               {
                $lnByte = ord(SubStr($tcStr, $iX, 1));
                $lnZ = $lnByte ^ ($lnCrc32 & 0x000000FF);
                $wert=$CRCTbl[$lnZ];
                if ($wert>0x7fffffff) $wert=$wert-4294967296;
                $lnCrc32 =  $wert ^ (($lnCrc32 >> 8) & 0x00ffffff);
               }

              $lnCrc32 = ~$lnCrc32;

              if($lnCRC32 < 0) $lnCRC32 = 4294967296 + $lnCRC32;

              Return $lnCrc32;

              ...

              dank für deine mühe,
              j.b.