| /******************************************************************************* |
| * Copyright 2014 Trevor Robinson |
| * |
| * Licensed 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 com.scurrilous.circe.impl; |
| |
| import java.nio.ByteBuffer; |
| import com.scurrilous.circe.StatefulHash; |
| |
| /** |
| * Base implementation for stateful hash functions. |
| */ |
| public abstract class AbstractStatefulHash implements StatefulHash { |
| |
| @Override |
| public boolean supportsUnsafe() { |
| return false; |
| } |
| |
| @Override |
| public void update(byte[] input) { |
| updateUnchecked(input, 0, input.length); |
| } |
| |
| @Override |
| public void update(byte[] input, int index, int length) { |
| if (length < 0) |
| throw new IllegalArgumentException(); |
| if (index < 0 || index + length > input.length) |
| throw new IndexOutOfBoundsException(); |
| updateUnchecked(input, index, length); |
| } |
| |
| @Override |
| public void update(ByteBuffer input) { |
| final byte[] array; |
| final int index; |
| final int length = input.remaining(); |
| if (input.hasArray()) { |
| array = input.array(); |
| index = input.arrayOffset() + input.position(); |
| input.position(input.limit()); |
| } else { |
| // convert to unsafe access if possible |
| if (input.isDirect() && supportsUnsafe()) { |
| long address = DirectByteBufferAccessLoader.getAddress(input); |
| if (address != 0) { |
| address += input.position(); |
| input.position(input.limit()); |
| update(address, length); |
| return; |
| } |
| } |
| |
| array = new byte[length]; |
| index = 0; |
| input.get(array); |
| } |
| updateUnchecked(array, index, length); |
| } |
| |
| @Override |
| public void update(long address, long length) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| /** |
| * Updates the state of this hash function with the given range of the given |
| * input array. The index and length parameters have already been validated. |
| * |
| * @param input the input array |
| * @param index the starting index of the first input byte |
| * @param length the length of the input range |
| */ |
| protected abstract void updateUnchecked(byte[] input, int index, int length); |
| |
| @Override |
| public byte[] getBytes() { |
| final byte[] array = new byte[length()]; |
| writeBytes(array, 0, array.length); |
| return array; |
| } |
| |
| @Override |
| public int getBytes(byte[] output, int index, int maxLength) { |
| if (maxLength < 0) |
| throw new IllegalArgumentException(); |
| if (index < 0 || index + maxLength > output.length) |
| throw new IndexOutOfBoundsException(); |
| final int length = Math.min(maxLength, length()); |
| writeBytes(output, index, length); |
| return length; |
| } |
| |
| /** |
| * Writes the output of this hash function into the given range of the given |
| * byte array. The inputs have already been validated. |
| * |
| * @param output the destination array for the output |
| * @param index the starting index of the first output byte |
| * @param length the number of bytes to write |
| */ |
| protected void writeBytes(byte[] output, int index, int length) { |
| long temp = getLong(); |
| for (int i = 0; i < length; ++i) { |
| output[index + i] = (byte) temp; |
| temp >>>= 8; |
| } |
| } |
| |
| @Override |
| public byte getByte() { |
| return (byte) getInt(); |
| } |
| |
| @Override |
| public short getShort() { |
| return (short) getInt(); |
| } |
| } |