blob: a8f2da5ba5569a9f6c26c9c467d02d6cf737fd6d [file] [log] [blame]
Mathias Agopian4ea13dc2013-05-06 20:20:50 -07001/*
2 * Copyright (C) 2005 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#include <binder/Debug.h>
18
19#include <utils/misc.h>
20
21#include <stdio.h>
22#include <stdlib.h>
23#include <ctype.h>
24
25namespace android {
26
27// ---------------------------------------------------------------------
28
29static const char indentStr[] =
30" "
31" ";
32
33const char* stringForIndent(int32_t indentLevel)
34{
35 ssize_t off = sizeof(indentStr)-1-(indentLevel*2);
36 return indentStr + (off < 0 ? 0 : off);
37}
38
39// ---------------------------------------------------------------------
40
Colin Crossf0487982014-02-05 17:42:44 -080041static void defaultPrintFunc(void* /*cookie*/, const char* txt)
Mathias Agopian4ea13dc2013-05-06 20:20:50 -070042{
43 printf("%s", txt);
44}
45
46// ---------------------------------------------------------------------
47
48static inline int isident(int c)
49{
50 return isalnum(c) || c == '_';
51}
52
53static inline bool isasciitype(char c)
54{
55 if( c >= ' ' && c < 127 && c != '\'' && c != '\\' ) return true;
56 return false;
57}
58
59static inline char makehexdigit(uint32_t val)
60{
61 return "0123456789abcdef"[val&0xF];
62}
63
64static char* appendhexnum(uint32_t val, char* out)
65{
66 for( int32_t i=28; i>=0; i-=4 ) {
67 *out++ = makehexdigit( val>>i );
68 }
69 *out = 0;
70 return out;
71}
72
73static char* appendcharornum(char c, char* out, bool skipzero = true)
74{
75 if (skipzero && c == 0) return out;
76
77 if (isasciitype(c)) {
78 *out++ = c;
79 return out;
80 }
81
82 *out++ = '\\';
83 *out++ = 'x';
84 *out++ = makehexdigit(c>>4);
85 *out++ = makehexdigit(c);
86 return out;
87}
88
89static char* typetostring(uint32_t type, char* out,
90 bool fullContext = true,
91 bool strict = false)
92{
93 char* pos = out;
94 char c[4];
95 c[0] = (char)((type>>24)&0xFF);
96 c[1] = (char)((type>>16)&0xFF);
97 c[2] = (char)((type>>8)&0xFF);
98 c[3] = (char)(type&0xFF);
99 bool valid;
100 if( !strict ) {
101 // now even less strict!
102 // valid = isasciitype(c[3]);
103 valid = true;
104 int32_t i = 0;
105 bool zero = true;
106 while (valid && i<3) {
107 if (c[i] == 0) {
108 if (!zero) valid = false;
109 } else {
110 zero = false;
111 //if (!isasciitype(c[i])) valid = false;
112 }
113 i++;
114 }
115 // if all zeros, not a valid type code.
116 if (zero) valid = false;
117 } else {
118 valid = isident(c[3]) ? true : false;
119 int32_t i = 0;
120 bool zero = true;
121 while (valid && i<3) {
122 if (c[i] == 0) {
123 if (!zero) valid = false;
124 } else {
125 zero = false;
126 if (!isident(c[i])) valid = false;
127 }
128 i++;
129 }
130 }
131 if( valid && (!fullContext || c[0] != '0' || c[1] != 'x') ) {
132 if( fullContext ) *pos++ = '\'';
133 pos = appendcharornum(c[0], pos);
134 pos = appendcharornum(c[1], pos);
135 pos = appendcharornum(c[2], pos);
136 pos = appendcharornum(c[3], pos);
137 if( fullContext ) *pos++ = '\'';
138 *pos = 0;
139 return pos;
140 }
Dan Austinf4865ca2015-10-21 11:28:59 -0700141
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700142 if( fullContext ) {
143 *pos++ = '0';
144 *pos++ = 'x';
145 }
146 return appendhexnum(type, pos);
147}
148
149void printTypeCode(uint32_t typeCode, debugPrintFunc func, void* cookie)
150{
151 char buffer[32];
152 char* end = typetostring(typeCode, buffer);
153 *end = 0;
154 func ? (*func)(cookie, buffer) : defaultPrintFunc(cookie, buffer);
155}
156
157void printHexData(int32_t indent, const void *buf, size_t length,
158 size_t bytesPerLine, int32_t singleLineBytesCutoff,
159 size_t alignment, bool cStyle,
160 debugPrintFunc func, void* cookie)
161{
162 if (alignment == 0) {
163 if (bytesPerLine >= 16) alignment = 4;
164 else if (bytesPerLine >= 8) alignment = 2;
165 else alignment = 1;
166 }
167 if (func == NULL) func = defaultPrintFunc;
168
169 size_t offset;
Dan Austinf4865ca2015-10-21 11:28:59 -0700170
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700171 unsigned char *pos = (unsigned char *)buf;
Dan Austinf4865ca2015-10-21 11:28:59 -0700172
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700173 if (pos == NULL) {
174 if (singleLineBytesCutoff < 0) func(cookie, "\n");
175 func(cookie, "(NULL)");
176 return;
177 }
Dan Austinf4865ca2015-10-21 11:28:59 -0700178
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700179 if (length == 0) {
180 if (singleLineBytesCutoff < 0) func(cookie, "\n");
181 func(cookie, "(empty)");
182 return;
183 }
Dan Austinf4865ca2015-10-21 11:28:59 -0700184
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700185 if ((int32_t)length < 0) {
186 if (singleLineBytesCutoff < 0) func(cookie, "\n");
187 char buf[64];
188 sprintf(buf, "(bad length: %zu)", length);
189 func(cookie, buf);
190 return;
191 }
Dan Austinf4865ca2015-10-21 11:28:59 -0700192
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700193 char buffer[256];
194 static const size_t maxBytesPerLine = (sizeof(buffer)-1-11-4)/(3+1);
Dan Austinf4865ca2015-10-21 11:28:59 -0700195
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700196 if (bytesPerLine > maxBytesPerLine) bytesPerLine = maxBytesPerLine;
Dan Austinf4865ca2015-10-21 11:28:59 -0700197
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700198 const bool oneLine = (int32_t)length <= singleLineBytesCutoff;
199 bool newLine = false;
200 if (cStyle) {
201 indent++;
202 func(cookie, "{\n");
203 newLine = true;
204 } else if (!oneLine) {
205 func(cookie, "\n");
206 newLine = true;
207 }
Dan Austinf4865ca2015-10-21 11:28:59 -0700208
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700209 for (offset = 0; ; offset += bytesPerLine, pos += bytesPerLine) {
210 long remain = length;
211
212 char* c = buffer;
213 if (!oneLine && !cStyle) {
214 sprintf(c, "0x%08x: ", (int)offset);
215 c += 12;
216 }
217
218 size_t index;
219 size_t word;
Dan Austinf4865ca2015-10-21 11:28:59 -0700220
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700221 for (word = 0; word < bytesPerLine; ) {
222
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700223 const size_t startIndex = word+(alignment-(alignment?1:0));
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700224
225 for (index = 0; index < alignment || (alignment == 0 && index < bytesPerLine); index++) {
Dan Austinf4865ca2015-10-21 11:28:59 -0700226
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700227 if (!cStyle) {
228 if (index == 0 && word > 0 && alignment > 0) {
229 *c++ = ' ';
230 }
Dan Austinf4865ca2015-10-21 11:28:59 -0700231
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700232 if (remain-- > 0) {
Dan Austinf4865ca2015-10-21 11:28:59 -0700233 const unsigned char val = *(pos+startIndex-index);
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700234 *c++ = makehexdigit(val>>4);
235 *c++ = makehexdigit(val);
236 } else if (!oneLine) {
237 *c++ = ' ';
238 *c++ = ' ';
239 }
240 } else {
241 if (remain > 0) {
242 if (index == 0 && word > 0) {
243 *c++ = ',';
244 *c++ = ' ';
245 }
246 if (index == 0) {
247 *c++ = '0';
248 *c++ = 'x';
249 }
Dan Austinf4865ca2015-10-21 11:28:59 -0700250 const unsigned char val = *(pos+startIndex-index);
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700251 *c++ = makehexdigit(val>>4);
252 *c++ = makehexdigit(val);
253 remain--;
254 }
255 }
256 }
Dan Austinf4865ca2015-10-21 11:28:59 -0700257
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700258 word += index;
259 }
260
261 if (!cStyle) {
262 remain = length;
263 *c++ = ' ';
264 *c++ = '\'';
265 for (index = 0; index < bytesPerLine; index++) {
266
267 if (remain-- > 0) {
268 const unsigned char val = pos[index];
269 *c++ = (val >= ' ' && val < 127) ? val : '.';
270 } else if (!oneLine) {
271 *c++ = ' ';
272 }
273 }
Dan Austinf4865ca2015-10-21 11:28:59 -0700274
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700275 *c++ = '\'';
276 if (length > bytesPerLine) *c++ = '\n';
277 } else {
278 if (remain > 0) *c++ = ',';
279 *c++ = '\n';
280 }
281
282 if (newLine && indent) func(cookie, stringForIndent(indent));
283 *c = 0;
284 func(cookie, buffer);
285 newLine = true;
Dan Austinf4865ca2015-10-21 11:28:59 -0700286
Mathias Agopian4ea13dc2013-05-06 20:20:50 -0700287 if (length <= bytesPerLine) break;
288 length -= bytesPerLine;
289 }
290
291 if (cStyle) {
292 if (indent > 0) func(cookie, stringForIndent(indent-1));
293 func(cookie, "};");
294 }
295}
296
297}; // namespace android
298