/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.hadoop.util; /** * Utility class to Concatenate two CRCs */ public class CrcConcat { /** * Lookup tables for calculating the CRC after adding zeros to a byte array from the original CRC. */ static final LookupTable[] lookupTables = { new LookupTable(256 * 1024 * 1024, CrcConcatLookupTables.T256mb), new LookupTable(16 * 1024 * 1024, CrcConcatLookupTables.T16mb), new LookupTable(1024 * 1024, CrcConcatLookupTables.T1mb), new LookupTable(16 * 1024, CrcConcatLookupTables.T16kb), new LookupTable(512, CrcConcatLookupTables.T512bytes), new LookupTable(64, CrcConcatLookupTables.T64bytes) }; /** * Lookup table for calculating the CRC after adding zeros to a byte array from the original CRC. * order is how many zeros are added. lookupTable is the lookup table for it. */ static class LookupTable { private LookupTable(int order, int[][] lookupTable) { this.order = order; this.lookupTable = lookupTable; } public int getOrder() { return order; } public int[][] getLookupTable() { return lookupTable; } int order; int[][] lookupTable; } /** * Helper function to transform a CRC using lookup table. Currently it is used * for calculating CRC after adding bytes zeros to source byte array. The special * lookup table needs to be passed in for this specific transformation * * @param crc * @param lookupTable * the first dimension is for which byte it applies to, the second * dimension is to lookup the byte and generate the outputs. * @return the result CRC */ static int transform(int crc, int[][] lookupTable) { int cb1 = lookupTable[0][crc & 0xff]; int cb2 = lookupTable[1][(crc >>>= 8) & 0xff]; int cb3 = lookupTable[2][(crc >>>= 8) & 0xff]; int cb4 = lookupTable[3][(crc >>>= 8) & 0xff]; return cb1 ^ cb2 ^ cb3 ^ cb4; } /** * Concatenate two CRCs * * @param crc1 * the CRC of the first byte array * @param crc2 * the CRC of the second byte array * @param order * the length of the second byte array * @return CRC of of the byte array, which is the concatenation of the two * byte arrays with given crc's */ static public int concatCrc(int crc1, int crc2, int order) { // Calculate CRC of crc1 + order's 0 int crcForCrc1 = crc1; int orderRemained = order; // Fast transforming CRCs for adding 0 to the end of the byte array by table // look-up for (LookupTable lookupTable : lookupTables) { while (orderRemained >= lookupTable.getOrder()) { crcForCrc1 = transform(crcForCrc1, lookupTable.getLookupTable()); orderRemained -= lookupTable.getOrder(); } } if (orderRemained > 0) { // We continue the first byte array's CRC calculating // and adding 0s to it. And then we plus it with CRC2 // // Doing that, we need to offset the CRC initial value of CRC2 by // subtracting a CRC value of empty string. // // For example, A1A2A3's CRC is C1C2C3C4, // while B1 B2 B3's CRc is C5C6C7C8 and we wnat to concatenate them, // it means (our initial value is FF FF FF FF): // FF FF FF FF A1 A2 A3 C1 C2 C3 C4 // FF FF FF FF B1 B2 B3 C5 C6 C7 C8 // both are multiple of generation polynomial. // By continue CRC by adding zeros, actually, we calculated // the CRC C1'C2'C3'C4, so that // FF FF FF FF A1 A2 A3 00 00 00 C1'C2'C3'C4' // is the multiple of generation polynomial. // By adding C5C6C7C8 and C1'C2'C3'C4', what we got is not // the CRC for // FF FF FF FF A1 A2 A3 B1 B2 B3 // which we expect, but this string plus: // FF FF FF FF 00 00 00 // To offset the impact, the only thing we need to do, is // to subtract the result by the CRC value for 00 00 00. // int initial = CrcConcatLookupTables.initCrcMap[orderRemained]; NativeCrc32 pjc = new NativeCrc32(); pjc.setValue(crcForCrc1); byte[] zeros = new byte[orderRemained]; pjc.update(zeros, 0, zeros.length); crcForCrc1 = (int) pjc.getValue() ^ initial; } return crcForCrc1 ^ crc2; } }