content: /*******************************************************************************
   * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
   * All rights reserved. This program and the accompanying materials
   * are made available under the terms of the Eclipse Public License v1.0
   * which accompanies this distribution, and is available at
   * http://www.eclipse.org/legal/epl-v10.html
   *
   * Contributors:
   *    Marc R. Hoffmann - initial API and implementation
   *    
   *******************************************************************************/
  package org.jacoco.core.internal.data;
  
  import org.objectweb.asm.Opcodes;
  
  /**
   * CRC64 checksum calculator based on the polynom specified in ISO 3309. The
   * implementation is based on the following publications:
   * 
   * <ul>
   * <li>http://en.wikipedia.org/wiki/Cyclic_redundancy_check</li>
   * <li>http://www.geocities.com/SiliconValley/Pines/8659/crc.htm</li>
   * </ul>
   */
  public final class CRC64 {
  
  	private static final long POLY64REV = 0xd800000000000000L;
  
  	private static final long[] LOOKUPTABLE;
  
  	static {
  		LOOKUPTABLE = new long[0x100];
  		for (int i = 0; i < 0x100; i++) {
  			long v = i;
  			for (int j = 0; j < 8; j++) {
  				if ((v & 1) == 1) {
  					v = (v >>> 1) ^ POLY64REV;
  				} else {
  					v = (v >>> 1);
  				}
  			}
  			LOOKUPTABLE[i] = v;
  		}
  	}
  
  	/**
  	 * Updates given checksum by given byte.
  	 *
  	 * @param sum
  	 *            initial checksum value
  	 * @param b
  	 *            byte to update the checksum with
  	 * @return updated checksum value
  	 */
  	private static long update(final long sum, final byte b) {
  		final int lookupidx = ((int) sum ^ b) & 0xff;
  		return (sum >>> 8) ^ LOOKUPTABLE[lookupidx];
  	}
  
  	/**
  	 * Updates given checksum by bytes from given array.
  	 *
  	 * @param sum
  	 *            initial checksum value
  	 * @param bytes
  	 *            byte array to update the checksum with
  	 * @param fromIndexInclusive
  	 *            start index in array, inclusive
  	 * @param toIndexExclusive
  	 *            end index in array, exclusive
  	 * @return updated checksum value
  	 */
  	private static long update(long sum, final byte[] bytes,
  			final int fromIndexInclusive, final int toIndexExclusive) {
  		for (int i = fromIndexInclusive; i < toIndexExclusive; i++) {
  			sum = update(sum, bytes[i]);
  		}
  		return sum;
  	}
  
  	/**
  	 * Calculates class identifier for the given class bytes.
  	 *
  	 * @param bytes
  	 *            class bytes
  	 * @return class identifier
  	 */
  	public static long classId(final byte[] bytes) {
  		if (bytes.length > 7 && bytes[6] == 0x00 && bytes[7] == Opcodes.V9) {
  			// To support early versions of Java 9 we did a trick - change of
  			// Java 9 class files version on Java 8. Unfortunately this also
  			// affected class identifiers.
  			long sum = update(0, bytes, 0, 7);
  			sum = update(sum, (byte) Opcodes.V1_8);
  			return update(sum, bytes, 8, bytes.length);
  		}
  		return update(0, bytes, 0, bytes.length);
  	}
  
  	private CRC64() {
  	}
  
  }
  