1 /*
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 
25 namespace android {
26 
27 // ---------------------------------------------------------------------
28 
29 static const char indentStr[] =
30 "                                                                            "
31 "                                                                            ";
32 
stringForIndent(int32_t indentLevel)33 const 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 
defaultPrintFunc(void *,const char * txt)41 static void defaultPrintFunc(void* /*cookie*/, const char* txt)
42 {
43     printf("%s", txt);
44 }
45 
46 // ---------------------------------------------------------------------
47 
isident(int c)48 static inline int isident(int c)
49 {
50     return isalnum(c) || c == '_';
51 }
52 
isasciitype(char c)53 static inline bool isasciitype(char c)
54 {
55     if( c >= ' ' && c < 127 && c != '\'' && c != '\\' ) return true;
56     return false;
57 }
58 
makehexdigit(uint32_t val)59 static inline char makehexdigit(uint32_t val)
60 {
61     return "0123456789abcdef"[val&0xF];
62 }
63 
appendhexnum(uint32_t val,char * out)64 static 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 
appendcharornum(char c,char * out,bool skipzero=true)73 static 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 
typetostring(uint32_t type,char * out,bool fullContext=true,bool strict=false)89 static 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     }
141 
142     if( fullContext ) {
143         *pos++ = '0';
144         *pos++ = 'x';
145     }
146     return appendhexnum(type, pos);
147 }
148 
printTypeCode(uint32_t typeCode,debugPrintFunc func,void * cookie)149 void 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 
printHexData(int32_t indent,const void * buf,size_t length,size_t bytesPerLine,int32_t singleLineBytesCutoff,size_t alignment,bool cStyle,debugPrintFunc func,void * cookie)157 void 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;
170 
171     unsigned char *pos = (unsigned char *)buf;
172 
173     if (pos == NULL) {
174         if (singleLineBytesCutoff < 0) func(cookie, "\n");
175         func(cookie, "(NULL)");
176         return;
177     }
178 
179     if (length == 0) {
180         if (singleLineBytesCutoff < 0) func(cookie, "\n");
181         func(cookie, "(empty)");
182         return;
183     }
184 
185     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     }
192 
193     char buffer[256];
194     static const size_t maxBytesPerLine = (sizeof(buffer)-1-11-4)/(3+1);
195 
196     if (bytesPerLine > maxBytesPerLine) bytesPerLine = maxBytesPerLine;
197 
198     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     }
208 
209     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;
220 
221         for (word = 0; word < bytesPerLine; ) {
222 
223             const size_t startIndex = word+(alignment-(alignment?1:0));
224             const ssize_t dir = -1;
225 
226             for (index = 0; index < alignment || (alignment == 0 && index < bytesPerLine); index++) {
227 
228                 if (!cStyle) {
229                     if (index == 0 && word > 0 && alignment > 0) {
230                         *c++ = ' ';
231                     }
232 
233                     if (remain-- > 0) {
234                         const unsigned char val = *(pos+startIndex+(index*dir));
235                         *c++ = makehexdigit(val>>4);
236                         *c++ = makehexdigit(val);
237                     } else if (!oneLine) {
238                         *c++ = ' ';
239                         *c++ = ' ';
240                     }
241                 } else {
242                     if (remain > 0) {
243                         if (index == 0 && word > 0) {
244                             *c++ = ',';
245                             *c++ = ' ';
246                         }
247                         if (index == 0) {
248                             *c++ = '0';
249                             *c++ = 'x';
250                         }
251                         const unsigned char val = *(pos+startIndex+(index*dir));
252                         *c++ = makehexdigit(val>>4);
253                         *c++ = makehexdigit(val);
254                         remain--;
255                     }
256                 }
257             }
258 
259             word += index;
260         }
261 
262         if (!cStyle) {
263             remain = length;
264             *c++ = ' ';
265             *c++ = '\'';
266             for (index = 0; index < bytesPerLine; index++) {
267 
268                 if (remain-- > 0) {
269                     const unsigned char val = pos[index];
270                     *c++ = (val >= ' ' && val < 127) ? val : '.';
271                 } else if (!oneLine) {
272                     *c++ = ' ';
273                 }
274             }
275 
276             *c++ = '\'';
277             if (length > bytesPerLine) *c++ = '\n';
278         } else {
279             if (remain > 0) *c++ = ',';
280             *c++ = '\n';
281         }
282 
283         if (newLine && indent) func(cookie, stringForIndent(indent));
284         *c = 0;
285         func(cookie, buffer);
286         newLine = true;
287 
288         if (length <= bytesPerLine) break;
289         length -= bytesPerLine;
290     }
291 
292     if (cStyle) {
293         if (indent > 0) func(cookie, stringForIndent(indent-1));
294         func(cookie, "};");
295     }
296 }
297 
298 }; // namespace android
299 
300