blob: f7988ecf1d1684224d3f9f3e43e61aeeb78dfd1c [file] [log] [blame]
The Android Open Source Projectd245d1d2008-10-21 07:00:00 -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 <utils/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
41static void defaultPrintFunc(void* cookie, const char* txt)
42{
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 inline char makeupperhexdigit(uint32_t val)
74{
75 return "0123456789ABCDEF"[val&0xF];
76}
77
78static char* appendupperhexnum(uint32_t val, char* out)
79{
80 for( int32_t i=28; i>=0; i-=4 ) {
81 *out++ = makeupperhexdigit( val>>i );
82 }
83 *out = 0;
84 return out;
85}
86
87static char* appendcharornum(char c, char* out, bool skipzero = true)
88{
89 if (skipzero && c == 0) return out;
90
91 if (isasciitype(c)) {
92 *out++ = c;
93 return out;
94 }
95
96 *out++ = '\\';
97 *out++ = 'x';
98 *out++ = makehexdigit(c>>4);
99 *out++ = makehexdigit(c);
100 return out;
101}
102
103static char* typetostring(uint32_t type, char* out,
104 bool fullContext = true,
105 bool strict = false)
106{
107 char* pos = out;
108 char c[4];
109 c[0] = (char)((type>>24)&0xFF);
110 c[1] = (char)((type>>16)&0xFF);
111 c[2] = (char)((type>>8)&0xFF);
112 c[3] = (char)(type&0xFF);
113 bool valid;
114 if( !strict ) {
115 // now even less strict!
116 // valid = isasciitype(c[3]);
117 valid = true;
118 int32_t i = 0;
119 bool zero = true;
120 while (valid && i<3) {
121 if (c[i] == 0) {
122 if (!zero) valid = false;
123 } else {
124 zero = false;
125 //if (!isasciitype(c[i])) valid = false;
126 }
127 i++;
128 }
129 // if all zeros, not a valid type code.
130 if (zero) valid = false;
131 } else {
132 valid = isident(c[3]) ? true : false;
133 int32_t i = 0;
134 bool zero = true;
135 while (valid && i<3) {
136 if (c[i] == 0) {
137 if (!zero) valid = false;
138 } else {
139 zero = false;
140 if (!isident(c[i])) valid = false;
141 }
142 i++;
143 }
144 }
145 if( valid && (!fullContext || c[0] != '0' || c[1] != 'x') ) {
146 if( fullContext ) *pos++ = '\'';
147 pos = appendcharornum(c[0], pos);
148 pos = appendcharornum(c[1], pos);
149 pos = appendcharornum(c[2], pos);
150 pos = appendcharornum(c[3], pos);
151 if( fullContext ) *pos++ = '\'';
152 *pos = 0;
153 return pos;
154 }
155
156 if( fullContext ) {
157 *pos++ = '0';
158 *pos++ = 'x';
159 }
160 return appendhexnum(type, pos);
161}
162
163void printTypeCode(uint32_t typeCode, debugPrintFunc func, void* cookie)
164{
165 char buffer[32];
166 char* end = typetostring(typeCode, buffer);
167 *end = 0;
168 func ? (*func)(cookie, buffer) : defaultPrintFunc(cookie, buffer);
169}
170
171void printHexData(int32_t indent, const void *buf, size_t length,
172 size_t bytesPerLine, int32_t singleLineBytesCutoff,
173 size_t alignment, bool cStyle,
174 debugPrintFunc func, void* cookie)
175{
176 if (alignment == 0) {
177 if (bytesPerLine >= 16) alignment = 4;
178 else if (bytesPerLine >= 8) alignment = 2;
179 else alignment = 1;
180 }
181 if (func == NULL) func = defaultPrintFunc;
182
183 size_t offset;
184
185 unsigned char *pos = (unsigned char *)buf;
186
187 if (pos == NULL) {
188 if (singleLineBytesCutoff < 0) func(cookie, "\n");
189 func(cookie, "(NULL)");
190 return;
191 }
192
193 if (length == 0) {
194 if (singleLineBytesCutoff < 0) func(cookie, "\n");
195 func(cookie, "(empty)");
196 return;
197 }
198
199 if ((int32_t)length < 0) {
200 if (singleLineBytesCutoff < 0) func(cookie, "\n");
201 char buf[64];
202 sprintf(buf, "(bad length: %d)", length);
203 func(cookie, buf);
204 return;
205 }
206
207 char buffer[256];
208 static const size_t maxBytesPerLine = (sizeof(buffer)-1-11-4)/(3+1);
209
210 if (bytesPerLine > maxBytesPerLine) bytesPerLine = maxBytesPerLine;
211
212 const bool oneLine = (int32_t)length <= singleLineBytesCutoff;
213 bool newLine = false;
214 if (cStyle) {
215 indent++;
216 func(cookie, "{\n");
217 newLine = true;
218 } else if (!oneLine) {
219 func(cookie, "\n");
220 newLine = true;
221 }
222
223 for (offset = 0; ; offset += bytesPerLine, pos += bytesPerLine) {
224 long remain = length;
225
226 char* c = buffer;
227 if (!oneLine && !cStyle) {
228 sprintf(c, "0x%08x: ", (int)offset);
229 c += 12;
230 }
231
232 size_t index;
233 size_t word;
234
235 for (word = 0; word < bytesPerLine; ) {
236
237#ifdef HAVE_LITTLE_ENDIAN
238 const size_t startIndex = word+(alignment-(alignment?1:0));
239 const ssize_t dir = -1;
240#else
241 const size_t startIndex = word;
242 const ssize_t dir = 1;
243#endif
244
245 for (index = 0; index < alignment || (alignment == 0 && index < bytesPerLine); index++) {
246
247 if (!cStyle) {
248 if (index == 0 && word > 0 && alignment > 0) {
249 *c++ = ' ';
250 }
251
252 if (remain-- > 0) {
253 const unsigned char val = *(pos+startIndex+(index*dir));
254 *c++ = makehexdigit(val>>4);
255 *c++ = makehexdigit(val);
256 } else if (!oneLine) {
257 *c++ = ' ';
258 *c++ = ' ';
259 }
260 } else {
261 if (remain > 0) {
262 if (index == 0 && word > 0) {
263 *c++ = ',';
264 *c++ = ' ';
265 }
266 if (index == 0) {
267 *c++ = '0';
268 *c++ = 'x';
269 }
270 const unsigned char val = *(pos+startIndex+(index*dir));
271 *c++ = makehexdigit(val>>4);
272 *c++ = makehexdigit(val);
273 remain--;
274 }
275 }
276 }
277
278 word += index;
279 }
280
281 if (!cStyle) {
282 remain = length;
283 *c++ = ' ';
284 *c++ = '\'';
285 for (index = 0; index < bytesPerLine; index++) {
286
287 if (remain-- > 0) {
288 const unsigned char val = pos[index];
289 *c++ = (val >= ' ' && val < 127) ? val : '.';
290 } else if (!oneLine) {
291 *c++ = ' ';
292 }
293 }
294
295 *c++ = '\'';
296 if (length > bytesPerLine) *c++ = '\n';
297 } else {
298 if (remain > 0) *c++ = ',';
299 *c++ = '\n';
300 }
301
302 if (newLine && indent) func(cookie, stringForIndent(indent));
303 *c = 0;
304 func(cookie, buffer);
305 newLine = true;
306
307 if (length <= bytesPerLine) break;
308 length -= bytesPerLine;
309 }
310
311 if (cStyle) {
312 if (indent > 0) func(cookie, stringForIndent(indent-1));
313 func(cookie, "};");
314 }
315}
316
317}; // namespace android
318