• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 android.cts.statsd.atom;
18 
19 import java.nio.charset.StandardCharsets;
20 import java.util.Formatter;
21 
22 /**
23  * Print utility for byte[].
24  */
25 public class BufferDebug {
26     private static final int HALF_WIDTH = 8;
27 
28     /**
29      * Number of bytes represented per row in hex output.
30      */
31     public static final int WIDTH = HALF_WIDTH * 2;
32 
33     /**
34      * Return a string suitable for debugging.
35      * - If the byte is printable as an ascii string, return that, in quotation marks,
36      *   with a newline at the end.
37      * - Otherwise, return the hexdump -C style output.
38      *
39      * @param buf the buffer
40      * @param max print up to _max_ bytes, or the length of the string. If max is 0,
41      *      print the whole contents of buf.
42      */
debugString(byte[] buf, int max)43     public static String debugString(byte[] buf, int max) {
44         if (buf == null) {
45             return "(null)";
46         }
47         if (buf.length == 0) {
48             return "(length 0)";
49         }
50 
51         int len = max;
52         if (len <= 0 || len > buf.length) {
53             max = len = buf.length;
54         }
55 
56         if (isPrintable(buf, len)) {
57             return "\"" + new String(buf, 0, len, StandardCharsets.UTF_8) + "\"\n";
58         } else {
59             return toHex(buf, len, max);
60         }
61     }
62 
toHex(byte[] buf, int len, int max)63     private static String toHex(byte[] buf, int len, int max) {
64         final StringBuilder str = new StringBuilder();
65 
66         // All but the last row
67         int rows = len / WIDTH;
68         for (int row = 0; row < rows; row++) {
69             writeRow(str, buf, row * WIDTH, WIDTH, max);
70         }
71 
72         // Last row
73         if (len % WIDTH != 0) {
74             writeRow(str, buf, rows * WIDTH, max - (rows * WIDTH), max);
75         }
76 
77         // Final len
78         str.append(String.format("%10d 0x%08x  ", buf.length, buf.length));
79         if (buf.length != max) {
80             str.append(String.format("truncated to %d 0x%08x", max, max));
81         }
82         str.append('\n');
83 
84         return str.toString();
85     }
86 
writeRow(StringBuilder str, byte[] buf, int start, int len, int max)87     private static void writeRow(StringBuilder str, byte[] buf, int start, int len, int max) {
88         final Formatter f = new Formatter(str);
89 
90         // Start index
91         f.format("%10d 0x%08x  ", start, start);
92 
93         // One past the last char we will print
94         int end = start + len;
95         // Number of missing caracters due to this being the last line.
96         int padding = 0;
97         if (start + WIDTH > max) {
98             padding = WIDTH - (end % WIDTH);
99             end = max;
100         }
101 
102         // Hex
103         for (int i = start; i < end; i++) {
104             f.format("%02x ", buf[i]);
105             if (i == start + HALF_WIDTH - 1) {
106                 str.append(" ");
107             }
108         }
109         for (int i = 0; i < padding; i++) {
110             str.append("   ");
111         }
112         if (padding >= HALF_WIDTH) {
113             str.append(" ");
114         }
115 
116         str.append("  ");
117         for (int i = start; i < end; i++) {
118             byte b = buf[i];
119             if (isPrintable(b)) {
120                 str.append((char)b);
121             } else {
122                 str.append('.');
123             }
124             if (i == start + HALF_WIDTH - 1) {
125                 str.append("  ");
126             }
127         }
128 
129         str.append('\n');
130     }
131 
isPrintable(byte[] buf, int len)132     private static boolean isPrintable(byte[] buf, int len) {
133         for (int i=0; i<len; i++) {
134             if (!isPrintable(buf[i])) {
135                 return false;
136             }
137         }
138         return true;
139     }
140 
isPrintable(byte c)141     private static boolean isPrintable(byte c) {
142         return c >= 0x20 && c <= 0x7e;
143     }
144 }
145