001/*
002 *   Copyright 2023 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;
019import java.io.UnsupportedEncodingException;
020
021
022/**
023 * Static helper methods for working with hex values.
024 */
025public class HexUtil {
026
027    private static final char[] HEX_CHARS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', };
028
029    private HexUtil() {
030        // This class may not be instantiated.
031    }
032
033    /**
034     * translate a byte array of raw data into a String with a hex representation of that data
035     *
036     * @param bytes raw binary data
037     *
038     * @return String Hex representation of the raw data
039     */
040    public static String bytesToHex(byte[] bytes) {
041        return bytesToHex(bytes, null);
042    }
043
044    /**
045     * translate a byte array of raw data into a String with a hex representation of that data.
046     * Each octet will be separated with a specific separator.
047     *
048     * @param bytes raw binary data
049     * @param separator This string will be injected into the output in between each octet in the stream
050     *
051     * @return String Hex representation of the raw data with each octet separated by 'separator'
052     */
053    public static String bytesToHex(byte[] bytes, String separator) {
054        StringBuilder tmpBuffer = new StringBuilder();
055        if (bytes != null) {
056            for (byte c : bytes) {
057                int b = c;
058                if (b < 0)
059                    b += 256;
060                if (separator != null)
061                    tmpBuffer.append(separator);
062                tmpBuffer.append(HEX_CHARS[(b & 0xf0) / 0x10]); // note, this benchmarks faster than using >> 4
063                tmpBuffer.append(HEX_CHARS[b & 0x0f]);
064            }
065        }
066        return tmpBuffer.toString();
067    }
068
069    /**
070     * Converts a Hex encoded String into a byte vector.
071     *
072     * @param str The String to be encoded.
073     *
074     * @return A byte vector representing the String.
075     */
076    public static byte[] hexToBytes(String str) {
077        if (str == null)
078            return null;
079        byte[] hexChars;
080        try {
081            hexChars = str.toUpperCase().getBytes("ISO_8859-1");
082        } catch (UnsupportedEncodingException e) {
083            throw new VonageUnexpectedException("ISO_8859_1 is an unsupported encoding in this JVM");
084        }
085        int size = hexChars.length;
086        byte[] bytes = new byte[size / 2];
087        int first;
088        int second;
089
090        int rIndex = 0;
091        // Convert to bytes.
092        for (int i = 0; i+1 <size; i= i + 2) {
093
094            // Convert first
095            first = hexChars[i];
096            if (first < 58)
097                first = ((first - 48) * 16); // 0 - 9
098            else
099                first = ((first - 55) * 16); // A - F
100
101            // Convert second
102            second = hexChars[i + 1];
103            if (second < 58)
104                second = second - 48; // 0 - 9
105            else
106                second = second - 55; // A - F
107
108            //Value must be between -128 and 127
109            int total = (first + second);
110            if (total > 127)
111                total = (256 + total);
112
113            bytes[rIndex] = (byte) total;
114            rIndex++;
115        }
116        return bytes;
117    }
118
119}