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 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 41 static void defaultPrintFunc(void* /*cookie*/, const char* txt) 42 { 43 printf("%s", txt); 44 } 45 46 // --------------------------------------------------------------------- 47 48 static inline int isident(int c) 49 { 50 return isalnum(c) || c == '_'; 51 } 52 53 static inline bool isasciitype(char c) 54 { 55 if( c >= ' ' && c < 127 && c != '\'' && c != '\\' ) return true; 56 return false; 57 } 58 59 static inline char makehexdigit(uint32_t val) 60 { 61 return "0123456789abcdef"[val&0xF]; 62 } 63 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 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 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 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 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 225 for (index = 0; index < alignment || (alignment == 0 && index < bytesPerLine); index++) { 226 227 if (!cStyle) { 228 if (index == 0 && word > 0 && alignment > 0) { 229 *c++ = ' '; 230 } 231 232 if (remain-- > 0) { 233 const unsigned char val = *(pos+startIndex-index); 234 *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 } 250 const unsigned char val = *(pos+startIndex-index); 251 *c++ = makehexdigit(val>>4); 252 *c++ = makehexdigit(val); 253 remain--; 254 } 255 } 256 } 257 258 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 } 274 275 *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; 286 287 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 299