2

I'm calculating CRC32 like code below :

import java.util.zip.CRC32;


String data = "99D5503012013165411";
    byte bytes[] = data.getBytes();
    Checksum checksum = new CRC32();
    checksum.update(bytes, 0, bytes.length);
    long checksumValue = checksum.getValue();
    System.out.println("Result of CRC32 : " +Long.toHexString(checksumValue) + " !");

when I compare my code with this online CRC32 calculation it only gives me the right result when the Input type ASCII, So there is a way to have the same result as Hex?

MrZ
  • 560
  • 2
  • 12

1 Answers1

1

Your problem is how you create the input (byte bytes[] = ...).

The String#getBytes method returns byte representation of individual characters in the string. But I suppose the input string 99D5503012013165411 is a hex representation of byte array.

So you have to convert it to bytes like here.

One byte is represented by two characters: see Hexadecimal on Wiki.


Update: There is another catch. One hex letter is 4bits, thus it is half of byte. A proper byte array written as hex string should be of even length.

This adds another level of confusion, since your example input is 19 chars long.

Working solution is (that gives output same as the online calc):

  public static void main(String[] args)
  {
    String data = "99D55030120131654101"; // notice the 01 at the end
    byte bytes[] = hexStringToByteArray(data);
    Checksum checksum = new CRC32();
    checksum.update(bytes, 0, bytes.length);
    long checksumValue = checksum.getValue();
    System.out.println("Result of CRC32 : " +Long.toHexString(checksumValue) + " !");
    // prints: Result of CRC32 : 9671cb4a !
  }

  // took from https://stackoverflow.com/a/140861/6749977 :
  public static byte[] hexStringToByteArray(String s) {
    int len = s.length();
    byte[] data = new byte[len / 2];
    for (int i = 0; i < len; i += 2) {
        data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                             + Character.digit(s.charAt(i+1), 16));
    }
    return data;
  }

The online tool you linked handles the missing letter by interpreting the last 1 as 01 (I had to change the input experimentally there). So I had to change the input to be of even length...

If you are going to get really input like this, and you are sure you want to handle the case this way, the hexStringToByteArray procedure should be updated. But be careful, I thing the right way would be to prepend the whole string with zeros to have even-length. Like an base-10 analogy: 132==0123


Update 2: Based on your comment here I add a solution with modified hexStringToByteArray method (even tough I feel a bit like doing your homework for you):

  public static void main(String[] args)
  {
    String data = "99D5503012013165411";
    String dataOnlyHexChars = data.replaceAll("[^0-9a-fA-F]", ""); // not very cool
    byte bytes[] = hexStringToByteArray(dataOnlyHexChars);
    Checksum checksum = new CRC32();
    checksum.update(bytes, 0, bytes.length);
    long checksumValue = checksum.getValue();
    System.out.println("Result of CRC32 : " +Long.toHexString(checksumValue) + " !");
    // prints: Result of CRC32 : 9671cb4a !
  }

  // took from https://stackoverflow.com/a/140861/6749977 and changed a bit :
  public static byte[] hexStringToByteArray(String s) {
    int len = s.length();
    byte[] data = new byte[(len + 1) / 2]; // changed
    for (int i = 0; i < len; i += 2) {
        if (len==i + 1) // changed
          data[i / 2] = (byte) Character.digit(s.charAt(i), 16);
        else
          data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                               + Character.digit(s.charAt(i+1), 16));
    }
    return data;
  }
Community
  • 1
  • 1
  • Update your other answer, rather than writing a new solution. – K Neeraj Lal Sep 02 '16 at 14:30
  • @KNeerajLal ok, next time :) My other answer was wrong, it pointed on non-issue, so it would not be _update_ but _delete_ and _write something totally different_ instead. – Martin Milichovsky Sep 02 '16 at 14:44
  • if work only for this 99D55030120131654101 if you try with this 98M25020920160758207 the result it's wrong – MrZ Sep 02 '16 at 14:52
  • `98M25020920160758207` is not much of a hex string, since it contains `M`, and hex alphabet is 0-9 and A-F. I put a bit effort to investigate the online tool, and what it does, is it skips not valid hex chars, so it effectively uses `9825020920160758207` as an input. This is not a very good way to compute hash/checksum -- when two very similar strings have the same output! – Martin Milichovsky Sep 02 '16 at 14:59