1 /* 2 * Copyright (C) 2025 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 package com.android.tradefed.result.resultdb; 17 18 import java.nio.charset.StandardCharsets; 19 20 /** Utility class for ResultDB reporter. */ 21 public final class ResultDBUtil { 22 23 /** Converts a byte array to a hexadecimal string. */ bytesToHex(byte[] bytes)24 public static String bytesToHex(byte[] bytes) { 25 StringBuilder sb = new StringBuilder(); 26 for (byte b : bytes) { 27 sb.append(String.format("%02x", b)); 28 } 29 return sb.toString(); 30 } 31 32 /** 33 * Truncates the string to the given max bytes, avoiding breaking up a multi-byte character. 34 * 35 * @param input the string to truncate 36 * @param maxBytes the maximum number of bytes (in utf-8 encoding) to truncate to 37 * @return the truncated string 38 */ truncateString(String input, int maxBytes)39 public static String truncateString(String input, int maxBytes) { 40 byte[] bytes = input.getBytes(StandardCharsets.UTF_8); 41 if (bytes.length <= maxBytes) { 42 return input; 43 } 44 45 int byteCount = 0; 46 StringBuilder result = new StringBuilder(); 47 48 for (int i = 0; i < input.length(); ) { 49 int codePoint = input.codePointAt(i); 50 byte[] codePointBytes = 51 new String(Character.toChars(codePoint)).getBytes(StandardCharsets.UTF_8); 52 53 if (byteCount + codePointBytes.length <= maxBytes) { 54 result.append(Character.toChars(codePoint)); 55 byteCount += codePointBytes.length; 56 i += Character.charCount(codePoint); // Move to the next code point 57 } else { 58 break; 59 } 60 } 61 return result.toString(); 62 } 63 64 /** 65 * Ensure the key is valid for ResultDB. 66 * 67 * <p>The key must match the regex: ^[a-z][a-z0-9_]*(/[a-z][a-z0-9_]*)*$ 68 */ makeValidKey(String key)69 public static String makeValidKey(String key) { 70 if (key == null || key.isEmpty()) { 71 return "empty_key"; 72 } 73 74 StringBuilder validKeyBuilder = new StringBuilder(); 75 for (char c : key.toCharArray()) { 76 if (c >= 'a' && c <= 'z') { 77 validKeyBuilder.append(c); 78 } else if (c >= '0' && c <= '9') { 79 validKeyBuilder.append(c); 80 } else if (c >= 'A' && c <= 'Z') { 81 validKeyBuilder.append((char) (c - 'A' + 'a')); 82 } else { 83 validKeyBuilder.append('_'); 84 } 85 } 86 String validKey = validKeyBuilder.toString(); 87 if (!validKey.isEmpty() && validKey.charAt(0) >= '0' && validKey.charAt(0) <= '9') { 88 validKey = "num_" + validKey; 89 } 90 return validKey; 91 } 92 } 93