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 <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 319