Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.server.wifi.util;
     18 
     19 import android.text.TextUtils;
     20 
     21 import com.android.server.wifi.ByteBufferReader;
     22 
     23 import libcore.util.HexEncoding;
     24 
     25 import java.nio.BufferUnderflowException;
     26 import java.nio.ByteBuffer;
     27 import java.nio.ByteOrder;
     28 import java.nio.CharBuffer;
     29 import java.nio.charset.CharacterCodingException;
     30 import java.nio.charset.CharsetDecoder;
     31 import java.nio.charset.StandardCharsets;
     32 import java.util.ArrayList;
     33 import java.util.Arrays;
     34 
     35 /**
     36  * Provide utility functions for native interfacing modules.
     37  */
     38 public class NativeUtil {
     39     private static final String ANY_MAC_STR = "any";
     40     public static final byte[] ANY_MAC_BYTES = {0, 0, 0, 0, 0, 0};
     41     private static final int MAC_LENGTH = 6;
     42     private static final int MAC_OUI_LENGTH = 3;
     43     private static final int MAC_STR_LENGTH = MAC_LENGTH * 2 + 5;
     44 
     45     /**
     46      * Convert the string to byte array list.
     47      *
     48      * @return the UTF_8 char byte values of str, as an ArrayList.
     49      * @throws IllegalArgumentException if a null string is sent.
     50      */
     51     public static ArrayList<Byte> stringToByteArrayList(String str) {
     52         if (str == null) {
     53             throw new IllegalArgumentException("null string");
     54         }
     55         ArrayList<Byte> byteArrayList = new ArrayList<Byte>();
     56         for (byte b : str.getBytes(StandardCharsets.UTF_8)) {
     57             byteArrayList.add(new Byte(b));
     58         }
     59         return byteArrayList;
     60     }
     61 
     62     /**
     63      * Convert the byte array list to string.
     64      *
     65      * @return the string decoded from UTF_8 byte values in byteArrayList.
     66      * @throws IllegalArgumentException if a null byte array list is sent.
     67      */
     68     public static String stringFromByteArrayList(ArrayList<Byte> byteArrayList) {
     69         if (byteArrayList == null) {
     70             throw new IllegalArgumentException("null byte array list");
     71         }
     72         byte[] byteArray = new byte[byteArrayList.size()];
     73         int i = 0;
     74         for (Byte b : byteArrayList) {
     75             byteArray[i] = b;
     76             i++;
     77         }
     78         return new String(byteArray, StandardCharsets.UTF_8);
     79     }
     80 
     81     /**
     82      * Convert the string to byte array.
     83      *
     84      * @return the UTF_8 char byte values of str, as an Array.
     85      * @throws IllegalArgumentException if a null string is sent.
     86      */
     87     public static byte[] stringToByteArray(String str) {
     88         if (str == null) {
     89             throw new IllegalArgumentException("null string");
     90         }
     91         return str.getBytes(StandardCharsets.UTF_8);
     92     }
     93 
     94     /**
     95      * Convert the byte array list to string.
     96      *
     97      * @return the string decoded from UTF_8 byte values in byteArray.
     98      * @throws IllegalArgumentException if a null byte array is sent.
     99      */
    100     public static String stringFromByteArray(byte[] byteArray) {
    101         if (byteArray == null) {
    102             throw new IllegalArgumentException("null byte array");
    103         }
    104         return new String(byteArray);
    105     }
    106 
    107     /**
    108      * Converts a mac address string to an array of Bytes.
    109      *
    110      * @param macStr string of format: "XX:XX:XX:XX:XX:XX" or "XXXXXXXXXXXX", where X is any
    111      *        hexadecimal digit.
    112      *        Passing null, empty string or "any" is the same as 00:00:00:00:00:00
    113      * @throws IllegalArgumentException for various malformed inputs.
    114      */
    115     public static byte[] macAddressToByteArray(String macStr) {
    116         if (TextUtils.isEmpty(macStr) || ANY_MAC_STR.equals(macStr)) return ANY_MAC_BYTES;
    117         String cleanMac = macStr.replace(":", "");
    118         if (cleanMac.length() != MAC_LENGTH * 2) {
    119             throw new IllegalArgumentException("invalid mac string length: " + cleanMac);
    120         }
    121         return HexEncoding.decode(cleanMac.toCharArray(), false);
    122     }
    123 
    124     /**
    125      * Converts an array of 6 bytes to a HexEncoded String with format: "XX:XX:XX:XX:XX:XX", where X
    126      * is any hexadecimal digit.
    127      *
    128      * @param macArray byte array of mac values, must have length 6
    129      * @throws IllegalArgumentException for malformed inputs.
    130      */
    131     public static String macAddressFromByteArray(byte[] macArray) {
    132         if (macArray == null) {
    133             throw new IllegalArgumentException("null mac bytes");
    134         }
    135         if (macArray.length != MAC_LENGTH) {
    136             throw new IllegalArgumentException("invalid macArray length: " + macArray.length);
    137         }
    138         StringBuilder sb = new StringBuilder(MAC_STR_LENGTH);
    139         for (int i = 0; i < macArray.length; i++) {
    140             if (i != 0) sb.append(":");
    141             sb.append(new String(HexEncoding.encode(macArray, i, 1)));
    142         }
    143         return sb.toString().toLowerCase();
    144     }
    145 
    146     /**
    147      * Converts a mac address OUI string to an array of Bytes.
    148      *
    149      * @param macStr string of format: "XX:XX:XX" or "XXXXXX", where X is any hexadecimal digit.
    150      * @throws IllegalArgumentException for various malformed inputs.
    151      */
    152     public static byte[] macAddressOuiToByteArray(String macStr) {
    153         if (macStr == null) {
    154             throw new IllegalArgumentException("null mac string");
    155         }
    156         String cleanMac = macStr.replace(":", "");
    157         if (cleanMac.length() != MAC_OUI_LENGTH * 2) {
    158             throw new IllegalArgumentException("invalid mac oui string length: " + cleanMac);
    159         }
    160         return HexEncoding.decode(cleanMac.toCharArray(), false);
    161     }
    162 
    163     /**
    164      * Converts an array of 6 bytes to a long representing the MAC address.
    165      *
    166      * @param macArray byte array of mac values, must have length 6
    167      * @return Long value of the mac address.
    168      * @throws IllegalArgumentException for malformed inputs.
    169      */
    170     public static Long macAddressToLong(byte[] macArray) {
    171         if (macArray == null) {
    172             throw new IllegalArgumentException("null mac bytes");
    173         }
    174         if (macArray.length != MAC_LENGTH) {
    175             throw new IllegalArgumentException("invalid macArray length: " + macArray.length);
    176         }
    177         try {
    178             return ByteBufferReader.readInteger(
    179                     ByteBuffer.wrap(macArray), ByteOrder.BIG_ENDIAN, macArray.length);
    180         } catch (BufferUnderflowException | IllegalArgumentException e) {
    181             throw new IllegalArgumentException("invalid macArray");
    182         }
    183     }
    184 
    185     /**
    186      * Remove enclosed quotes of the provided string.
    187      *
    188      * @param quotedStr String to be unquoted.
    189      * @return String without the enclosing quotes.
    190      */
    191     public static String removeEnclosingQuotes(String quotedStr) {
    192         int length = quotedStr.length();
    193         if ((length >= 2)
    194                 && (quotedStr.charAt(0) == '"') && (quotedStr.charAt(length - 1) == '"')) {
    195             return quotedStr.substring(1, length - 1);
    196         }
    197         return quotedStr;
    198     }
    199 
    200     /**
    201      * Add enclosing quotes of the provided string.
    202      *
    203      * @param str String to be uoted.
    204      * @return String with the enclosing quotes.
    205      */
    206     public static String addEnclosingQuotes(String str) {
    207         return "\"" + str + "\"";
    208     }
    209 
    210     /**
    211      * Converts an string to an arraylist of UTF_8 byte values.
    212      * These forms are acceptable:
    213      * a) UTF-8 String encapsulated in quotes, or
    214      * b) Hex string with no delimiters.
    215      *
    216      * @param str String to be converted.
    217      * @throws IllegalArgumentException for null string.
    218      */
    219     public static ArrayList<Byte> hexOrQuotedStringToBytes(String str) {
    220         if (str == null) {
    221             throw new IllegalArgumentException("null string");
    222         }
    223         int length = str.length();
    224         if ((length > 1) && (str.charAt(0) == '"') && (str.charAt(length - 1) == '"')) {
    225             str = str.substring(1, str.length() - 1);
    226             return stringToByteArrayList(str);
    227         } else {
    228             return byteArrayToArrayList(hexStringToByteArray(str));
    229         }
    230     }
    231 
    232     /**
    233      * Converts an ArrayList<Byte> of UTF_8 byte values to string.
    234      * The string will either be:
    235      * a) UTF-8 String encapsulated in quotes (if all the bytes are UTF-8 encodeable and non null),
    236      * or
    237      * b) Hex string with no delimiters.
    238      *
    239      * @param bytes List of bytes for ssid.
    240      * @throws IllegalArgumentException for null bytes.
    241      */
    242     public static String bytesToHexOrQuotedString(ArrayList<Byte> bytes) {
    243         if (bytes == null) {
    244             throw new IllegalArgumentException("null ssid bytes");
    245         }
    246         byte[] byteArray = byteArrayFromArrayList(bytes);
    247         // Check for 0's in the byte stream in which case we cannot convert this into a string.
    248         if (!bytes.contains(Byte.valueOf((byte) 0))) {
    249             CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder();
    250             try {
    251                 CharBuffer decoded = decoder.decode(ByteBuffer.wrap(byteArray));
    252                 return "\"" + decoded.toString() + "\"";
    253             } catch (CharacterCodingException cce) {
    254             }
    255         }
    256         return hexStringFromByteArray(byteArray);
    257     }
    258 
    259     /**
    260      * Converts an ssid string to an arraylist of UTF_8 byte values.
    261      * These forms are acceptable:
    262      * a) UTF-8 String encapsulated in quotes, or
    263      * b) Hex string with no delimiters.
    264      *
    265      * @param ssidStr String to be converted.
    266      * @throws IllegalArgumentException for null string.
    267      */
    268     public static ArrayList<Byte> decodeSsid(String ssidStr) {
    269         return hexOrQuotedStringToBytes(ssidStr);
    270     }
    271 
    272     /**
    273      * Converts an ArrayList<Byte> of UTF_8 byte values to ssid string.
    274      * The string will either be:
    275      * a) UTF-8 String encapsulated in quotes (if all the bytes are UTF-8 encodeable and non null),
    276      * or
    277      * b) Hex string with no delimiters.
    278      *
    279      * @param ssidBytes List of bytes for ssid.
    280      * @throws IllegalArgumentException for null bytes.
    281      */
    282     public static String encodeSsid(ArrayList<Byte> ssidBytes) {
    283         return bytesToHexOrQuotedString(ssidBytes);
    284     }
    285 
    286     /**
    287      * Convert from an array of primitive bytes to an array list of Byte.
    288      */
    289     public static ArrayList<Byte> byteArrayToArrayList(byte[] bytes) {
    290         ArrayList<Byte> byteList = new ArrayList<>();
    291         for (Byte b : bytes) {
    292             byteList.add(b);
    293         }
    294         return byteList;
    295     }
    296 
    297     /**
    298      * Convert from an array list of Byte to an array of primitive bytes.
    299      */
    300     public static byte[] byteArrayFromArrayList(ArrayList<Byte> bytes) {
    301         byte[] byteArray = new byte[bytes.size()];
    302         int i = 0;
    303         for (Byte b : bytes) {
    304             byteArray[i++] = b;
    305         }
    306         return byteArray;
    307     }
    308 
    309     /**
    310      * Converts a hex string to byte array.
    311      *
    312      * @param hexStr String to be converted.
    313      * @throws IllegalArgumentException for null string.
    314      */
    315     public static byte[] hexStringToByteArray(String hexStr) {
    316         if (hexStr == null) {
    317             throw new IllegalArgumentException("null hex string");
    318         }
    319         return HexEncoding.decode(hexStr.toCharArray(), false);
    320     }
    321 
    322     /**
    323      * Converts a byte array to hex string.
    324      *
    325      * @param bytes List of bytes for ssid.
    326      * @throws IllegalArgumentException for null bytes.
    327      */
    328     public static String hexStringFromByteArray(byte[] bytes) {
    329         if (bytes == null) {
    330             throw new IllegalArgumentException("null hex bytes");
    331         }
    332         return new String(HexEncoding.encode(bytes)).toLowerCase();
    333     }
    334 
    335     /**
    336      * Converts an 8 byte array to a WPS device type string
    337      * { 0, 1, 2, -1, 4, 5, 6, 7 } --> "1-02FF0405-1543";
    338      */
    339     public static String wpsDevTypeStringFromByteArray(byte[] devType) {
    340         byte[] a = devType;
    341         int x = ((a[0] & 0xFF) << 8) | (a[1] & 0xFF);
    342         String y = new String(HexEncoding.encode(Arrays.copyOfRange(devType, 2, 6)));
    343         int z = ((a[6] & 0xFF) << 8) | (a[7] & 0xFF);
    344         return String.format("%d-%s-%d", x, y, z);
    345     }
    346 }
    347