001/**
002 * Copyright 2017, Digi International Inc.
003 *
004 * This Source Code Form is subject to the terms of the Mozilla Public
005 * License, v. 2.0. If a copy of the MPL was not distributed with this
006 * file, you can obtain one at http://mozilla.org/MPL/2.0/.
007 *
008 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 
009 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 
010 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 
011 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 
012 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
013 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
014 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
015 */
016package com.digi.xbee.api.utils;
017
018/**
019 * Utility class containing methods to work with hexadecimal values and several 
020 * data type conversions.
021 */
022public class HexUtils {
023
024        // Constants.
025        private static final String HEXES = "0123456789ABCDEF";
026        private static final String HEX_HEADER = "0x";
027        
028        /**
029         * Converts the given byte array into an hex string.
030         * 
031         * @param value Byte array to convert to hex string.
032         * 
033         * @return Converted byte array to hex string.
034         * 
035         * @throws NullPointerException if {@code value == null}.
036         * 
037         * @see #hexStringToByteArray(String)
038         */
039        public static String byteArrayToHexString(byte[] value) {
040                if (value == null )
041                        throw new NullPointerException("Value to convert cannot be null.");
042                
043                final StringBuilder hex = new StringBuilder(2 * value.length );
044                for (final byte b : value) {
045                        hex.append(HEXES.charAt((b & 0xF0) >> 4))
046                                .append(HEXES.charAt((b & 0x0F)));
047                }
048                return hex.toString();
049        }
050        
051        /**
052         * Converts the given byte into an hex string.
053         * 
054         * @param value Byte to convert to hex string.
055         * 
056         * @return Converted byte to hex string.
057         */
058        public static String byteToHexString(byte value) {
059                final StringBuilder hex = new StringBuilder(2);
060                byte b = value;
061                hex.append(HEXES.charAt((b & 0xF0) >> 4))
062                        .append(HEXES.charAt((b & 0x0F)));
063                return hex.toString();
064        }
065        
066        /**
067         * Converts the given hex string into a byte array.
068         * 
069         * @param value Hex string to convert to byte array.
070         * 
071         * @return Byte array of the given hex string.
072         * 
073         * @throws NullPointerException if {@code value == null}.
074         * 
075         * @see #byteArrayToHexString(byte[])
076         */
077        public static byte[] hexStringToByteArray(String value) {
078                if (value == null)
079                        throw new NullPointerException("Value to convert cannot be null.");
080                
081                value = value.trim();
082                if (value.startsWith(HEX_HEADER))
083                        value = value.substring((HEX_HEADER).length());
084                int len = value.length();
085                if (len % 2 != 0) {
086                        value = "0" + value;
087                        len = value.length();
088                }
089                byte[] data = new byte[len / 2];
090                for (int i = 0; i < len; i += 2) {
091                        data[i / 2] = (byte) ((Character.digit(value.charAt(i), 16) << 4)
092                                        + Character.digit(value.charAt(i+1), 16));
093                }
094                return data;
095        }
096        
097        /**
098         * Checks whether the given parameter is a string or a numeric value.
099         * 
100         * @param parameter Parameter to check.
101         * 
102         * @return {@code true} if the given parameter is a string,
103         *         {@code false} otherwise.
104         * 
105         * @throws NullPointerException if {@code parameter == null}.
106         */
107        public static boolean containsLetters(String parameter) {
108                if (parameter == null)
109                        throw new NullPointerException("Parameter cannot be null.");
110                
111                byte[] byteArray = parameter.getBytes();
112                for (int i = 0; i < byteArray.length; i++){
113                        if (!((byteArray[i] >= '0') && (byteArray[i] <= '9')))
114                                return true;
115                }
116                return false;
117        }
118        
119        /**
120         * Converts the given integer into an hexadecimal string.
121         * 
122         * @param value The integer value to convert to hexadecimal string.
123         * @param minBytes The minimum number of bytes to be represented.
124         * 
125         * @return The integer value as hexadecimal string.
126         * 
127         * @throws IllegalArgumentException if {@code minBytes <= 0}.
128         */
129        public static String integerToHexString(int value, int minBytes) {
130                if (minBytes <= 0)
131                        throw new IllegalArgumentException("Minimum number of bytes must be greater than 0.");
132                
133                String f = String.format("%%0%dX", minBytes*2);
134                return String.format(f, value);
135        }
136        
137        /**
138         * Converts the given hexadecimal string to a pretty format by splitting the 
139         * content byte by byte.
140         * 
141         * @param hexString The hexadecimal string to convert.
142         * 
143         * @return The hexadecimal string with pretty format.
144         * 
145         * @throws NullPointerException if {@code hexString == null}.
146         * 
147         * @see #prettyHexString(byte[])
148         */
149        public static String prettyHexString(String hexString) {
150                if (hexString == null)
151                        throw new NullPointerException("Hexadecimal string cannot be null.");
152                
153                String copy = hexString.toUpperCase();
154                for (final char c : copy.toCharArray()) {
155                        if (!HEXES.contains(""+c))
156                                throw new IllegalArgumentException("Given string cannot contain non-hexadecimal characters.");
157                }
158                
159                String prettyHexString = "";
160                if (copy.length() % 2 != 0)
161                        copy = "0" + copy;
162                int iterations = copy.length() / 2;
163                for (int i = 0; i < iterations; i++)
164                        prettyHexString += copy.substring(2 * i, 2 * i + 2) + " ";
165                return prettyHexString.trim();
166        }
167        
168        /**
169         * Converts the given byte array into an hex string and retrieves it 
170         * in pretty format by splitting the content byte by byte.
171         * 
172         * @param value The byte array to convert to pretty hex string.
173         * 
174         * @return The hexadecimal pretty string.
175         * 
176         * @throws NullPointerException if {@code value == null}.
177         * 
178         * @see #prettyHexString(String)
179         */
180        public static String prettyHexString(byte[] value) {
181                return prettyHexString(byteArrayToHexString(value));
182        }
183}