001/*
002 *   Copyright 2020 Vonage
003 *
004 *   Licensed under the Apache License, Version 2.0 (the "License");
005 *   you may not use this file except in compliance with the License.
006 *   You may obtain a copy of the License at
007 *
008 *        http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *   Unless required by applicable law or agreed to in writing, software
011 *   distributed under the License is distributed on an "AS IS" BASIS,
012 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *   See the License for the specific language governing permissions and
014 *   limitations under the License.
015 */
016package com.vonage.client.sms;
017
018import com.vonage.client.VonageUnexpectedException;
019
020import java.io.UnsupportedEncodingException;
021
022
023/**
024 * Static helper methods for working with hex values.
025 *
026 * @author Paul Cook
027 */
028public class HexUtil {
029
030    private static final char[] HEX_CHARS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', };
031
032    private HexUtil() {
033        // This class may not be instantiated.
034    }
035
036    /**
037     * translate a byte array of raw data into a String with a hex representation of that data
038     *
039     * @param bytes raw binary data
040     *
041     * @return String Hex representation of the raw data
042     */
043    public static String bytesToHex(byte[] bytes) {
044        return bytesToHex(bytes, null);
045    }
046
047    /**
048     * translate a byte array of raw data into a String with a hex representation of that data.
049     * Each octet will be separated with a specific separator.
050     *
051     * @param bytes raw binary data
052     * @param separator This string will be injected into the output in between each octet in the stream
053     *
054     * @return String Hex representation of the raw data with each octet separated by 'separator'
055     */
056    public static String bytesToHex(byte[] bytes, String separator) {
057        StringBuilder tmpBuffer = new StringBuilder();
058        if (bytes != null) {
059            for (byte c : bytes) {
060                int b = c;
061                if (b < 0)
062                    b += 256;
063                if (separator != null)
064                    tmpBuffer.append(separator);
065                tmpBuffer.append(HEX_CHARS[(b & 0xf0) / 0x10]); // note, this benchmarks faster than using >> 4
066                tmpBuffer.append(HEX_CHARS[b & 0x0f]);
067            }
068        }
069        return tmpBuffer.toString();
070    }
071
072    /**
073     * Converts a Hex encoded String into a byte vector.
074     *
075     * @param str The String to be encoded.
076     *
077     * @return A byte vector representing the String.
078     */
079    public static byte[] hexToBytes(String str) {
080        if (str == null)
081            return null;
082        byte[] hexChars;
083        try {
084            hexChars = str.toUpperCase().getBytes("ISO_8859-1");
085        } catch (UnsupportedEncodingException e) {
086            throw new VonageUnexpectedException("ISO_8859_1 is an unsupported encoding in this JVM");
087        }
088        int size = hexChars.length;
089        byte[] bytes = new byte[size / 2];
090        int first;
091        int second;
092
093        int rIndex = 0;
094        // Convert to bytes.
095        for (int i = 0; i+1 <size; i= i + 2) {
096
097            // Convert first
098            first = hexChars[i];
099            if (first < 58)
100                first = ((first - 48) * 16); // 0 - 9
101            else
102                first = ((first - 55) * 16); // A - F
103
104            // Convert second
105            second = hexChars[i + 1];
106            if (second < 58)
107                second = second - 48; // 0 - 9
108            else
109                second = second - 55; // A - F
110
111            //Value must be between -128 and 127
112            int total = (first + second);
113            if (total > 127)
114                total = (256 + total);
115
116            bytes[rIndex] = (byte) total;
117            rIndex++;
118        }
119        return bytes;
120    }
121
122}