1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 module hunt.shiro.codec.Hex; 20 21 import hunt.Exceptions; 22 import hunt.text.CharacterData; 23 24 import std.conv; 25 26 /** 27 * <a href="http://en.wikipedia.org/wiki/Hexadecimal">Hexadecimal</a> encoder and decoder. 28 * <p/> 29 * This class was borrowed from Apache Commons Codec SVN repository (rev. {@code 560660}) with modifications 30 * to enable Hex conversion without a full dependency on Commons Codec. We didn't want to reinvent the wheel of 31 * great work they've done, but also didn't want to force every Shiro user to depend on the commons-codec.jar 32 * <p/> 33 * As per the Apache 2.0 license, the original copyright notice and all author and copyright information have 34 * remained in tact. 35 * 36 * @see <a href="http://en.wikipedia.org/wiki/Hexadecimal">Wikipedia: Hexadecimal</a> 37 * @since 0.9 38 */ 39 class Hex { 40 41 /** 42 * Used to build output as Hex 43 */ 44 private enum char[] DIGITS = [ 45 '0', '1', '2', '3', '4', '5', '6', '7', 46 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' 47 ]; 48 49 /** 50 * Encodes the specified byte array to a character array and then returns that character array 51 * as a string. 52 * 53 * @param bytes the byte array to Hex-encode. 54 * @return A string representation of the resultant hex-encoded char array. 55 */ 56 static string encodeToString(byte[] bytes) { 57 char[] encodedChars = encode(bytes); 58 return cast(string)(encodedChars); 59 } 60 61 /** 62 * Converts an array of bytes into an array of characters representing the hexadecimal values of each byte in order. 63 * The returned array will be double the length of the passed array, as it takes two characters to represent any 64 * given byte. 65 * 66 * @param data byte[] to convert to Hex characters 67 * @return A char[] containing hexadecimal characters 68 */ 69 static char[] encode(byte[] data) { 70 int l = cast(int)data.length; 71 char[] o = new char[l << 1]; 72 73 // two characters form the hex value. 74 for (int i = 0, j = 0; i < l; i++) { 75 o[j++] = DIGITS[(0xF0 & data[i]) >>> 4]; 76 o[j++] = DIGITS[0x0F & data[i]]; 77 } 78 79 return o; 80 } 81 82 /** 83 * Converts an array of character bytes representing hexadecimal values into an 84 * array of bytes of those same values. The returned array will be half the 85 * length of the passed array, as it takes two characters to represent any 86 * given byte. An exception is thrown if the passed char array has an odd 87 * number of elements. 88 * 89 * @param array An array of character bytes containing hexadecimal digits 90 * @return A byte array containing binary data decoded from 91 * the supplied byte array (representing characters). 92 * @throws IllegalArgumentException Thrown if an odd number of characters is supplied 93 * to this function 94 * @see #decode(char[]) 95 */ 96 static byte[] decode(byte[] array) { 97 return decode(cast(char[])array); 98 } 99 100 /** 101 * Converts the specified Hex-encoded string into a raw byte array. This is a 102 * convenience method that merely delegates to {@link #decode(char[])} using the 103 * argument's hex.toCharArray() value. 104 * 105 * @param hex a Hex-encoded string. 106 * @return A byte array containing binary data decoded from the supplied string's char array. 107 */ 108 static byte[] decode(string hex) { 109 return decode(cast(char[])hex); 110 } 111 112 /** 113 * Converts an array of characters representing hexadecimal values into an 114 * array of bytes of those same values. The returned array will be half the 115 * length of the passed array, as it takes two characters to represent any 116 * given byte. An exception is thrown if the passed char array has an odd 117 * number of elements. 118 * 119 * @param data An array of characters containing hexadecimal digits 120 * @return A byte array containing binary data decoded from 121 * the supplied char array. 122 * @throws IllegalArgumentException if an odd number or illegal of characters 123 * is supplied 124 */ 125 static byte[] decode(char[] data) { 126 int len = cast(int)data.length; 127 if ((len & 0x01) != 0) { 128 throw new IllegalArgumentException("Odd number of characters."); 129 } 130 131 byte[] o = new byte[len >> 1]; 132 133 // two characters form the hex value. 134 for (int i = 0, j = 0; j < len; i++) { 135 int f = toDigit(data[j], j) << 4; 136 j++; 137 f = f | toDigit(data[j], j); 138 j++; 139 o[i] = cast(byte) (f & 0xFF); 140 } 141 142 return o; 143 } 144 145 /** 146 * Converts a hexadecimal character to an integer. 147 * 148 * @param ch A character to convert to an integer digit 149 * @param index The index of the character in the source 150 * @return An integer 151 * @throws IllegalArgumentException if ch is an illegal hex character 152 */ 153 protected static int toDigit(char ch, int index) { 154 int digit = CharacterHelper.digit(ch, 16); 155 if (digit == -1) { 156 throw new IllegalArgumentException("Illegal hexadecimal character " ~ 157 ch.to!string() ~ " at index " ~ index.to!string()); 158 } 159 return digit; 160 } 161 162 }