diff options
Diffstat (limited to 'libs/utils/Debug.cpp')
-rw-r--r-- | libs/utils/Debug.cpp | 318 |
1 files changed, 318 insertions, 0 deletions
diff --git a/libs/utils/Debug.cpp b/libs/utils/Debug.cpp new file mode 100644 index 0000000..f7988ec --- /dev/null +++ b/libs/utils/Debug.cpp @@ -0,0 +1,318 @@ +/* + * Copyright (C) 2005 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <utils/Debug.h> + +#include <utils/misc.h> + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> + +namespace android { + +// --------------------------------------------------------------------- + +static const char indentStr[] = +" " +" "; + +const char* stringForIndent(int32_t indentLevel) +{ + ssize_t off = sizeof(indentStr)-1-(indentLevel*2); + return indentStr + (off < 0 ? 0 : off); +} + +// --------------------------------------------------------------------- + +static void defaultPrintFunc(void* cookie, const char* txt) +{ + printf("%s", txt); +} + +// --------------------------------------------------------------------- + +static inline int isident(int c) +{ + return isalnum(c) || c == '_'; +} + +static inline bool isasciitype(char c) +{ + if( c >= ' ' && c < 127 && c != '\'' && c != '\\' ) return true; + return false; +} + +static inline char makehexdigit(uint32_t val) +{ + return "0123456789abcdef"[val&0xF]; +} + +static char* appendhexnum(uint32_t val, char* out) +{ + for( int32_t i=28; i>=0; i-=4 ) { + *out++ = makehexdigit( val>>i ); + } + *out = 0; + return out; +} + +static inline char makeupperhexdigit(uint32_t val) +{ + return "0123456789ABCDEF"[val&0xF]; +} + +static char* appendupperhexnum(uint32_t val, char* out) +{ + for( int32_t i=28; i>=0; i-=4 ) { + *out++ = makeupperhexdigit( val>>i ); + } + *out = 0; + return out; +} + +static char* appendcharornum(char c, char* out, bool skipzero = true) +{ + if (skipzero && c == 0) return out; + + if (isasciitype(c)) { + *out++ = c; + return out; + } + + *out++ = '\\'; + *out++ = 'x'; + *out++ = makehexdigit(c>>4); + *out++ = makehexdigit(c); + return out; +} + +static char* typetostring(uint32_t type, char* out, + bool fullContext = true, + bool strict = false) +{ + char* pos = out; + char c[4]; + c[0] = (char)((type>>24)&0xFF); + c[1] = (char)((type>>16)&0xFF); + c[2] = (char)((type>>8)&0xFF); + c[3] = (char)(type&0xFF); + bool valid; + if( !strict ) { + // now even less strict! + // valid = isasciitype(c[3]); + valid = true; + int32_t i = 0; + bool zero = true; + while (valid && i<3) { + if (c[i] == 0) { + if (!zero) valid = false; + } else { + zero = false; + //if (!isasciitype(c[i])) valid = false; + } + i++; + } + // if all zeros, not a valid type code. + if (zero) valid = false; + } else { + valid = isident(c[3]) ? true : false; + int32_t i = 0; + bool zero = true; + while (valid && i<3) { + if (c[i] == 0) { + if (!zero) valid = false; + } else { + zero = false; + if (!isident(c[i])) valid = false; + } + i++; + } + } + if( valid && (!fullContext || c[0] != '0' || c[1] != 'x') ) { + if( fullContext ) *pos++ = '\''; + pos = appendcharornum(c[0], pos); + pos = appendcharornum(c[1], pos); + pos = appendcharornum(c[2], pos); + pos = appendcharornum(c[3], pos); + if( fullContext ) *pos++ = '\''; + *pos = 0; + return pos; + } + + if( fullContext ) { + *pos++ = '0'; + *pos++ = 'x'; + } + return appendhexnum(type, pos); +} + +void printTypeCode(uint32_t typeCode, debugPrintFunc func, void* cookie) +{ + char buffer[32]; + char* end = typetostring(typeCode, buffer); + *end = 0; + func ? (*func)(cookie, buffer) : defaultPrintFunc(cookie, buffer); +} + +void 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) +{ + if (alignment == 0) { + if (bytesPerLine >= 16) alignment = 4; + else if (bytesPerLine >= 8) alignment = 2; + else alignment = 1; + } + if (func == NULL) func = defaultPrintFunc; + + size_t offset; + + unsigned char *pos = (unsigned char *)buf; + + if (pos == NULL) { + if (singleLineBytesCutoff < 0) func(cookie, "\n"); + func(cookie, "(NULL)"); + return; + } + + if (length == 0) { + if (singleLineBytesCutoff < 0) func(cookie, "\n"); + func(cookie, "(empty)"); + return; + } + + if ((int32_t)length < 0) { + if (singleLineBytesCutoff < 0) func(cookie, "\n"); + char buf[64]; + sprintf(buf, "(bad length: %d)", length); + func(cookie, buf); + return; + } + + char buffer[256]; + static const size_t maxBytesPerLine = (sizeof(buffer)-1-11-4)/(3+1); + + if (bytesPerLine > maxBytesPerLine) bytesPerLine = maxBytesPerLine; + + const bool oneLine = (int32_t)length <= singleLineBytesCutoff; + bool newLine = false; + if (cStyle) { + indent++; + func(cookie, "{\n"); + newLine = true; + } else if (!oneLine) { + func(cookie, "\n"); + newLine = true; + } + + for (offset = 0; ; offset += bytesPerLine, pos += bytesPerLine) { + long remain = length; + + char* c = buffer; + if (!oneLine && !cStyle) { + sprintf(c, "0x%08x: ", (int)offset); + c += 12; + } + + size_t index; + size_t word; + + for (word = 0; word < bytesPerLine; ) { + +#ifdef HAVE_LITTLE_ENDIAN + const size_t startIndex = word+(alignment-(alignment?1:0)); + const ssize_t dir = -1; +#else + const size_t startIndex = word; + const ssize_t dir = 1; +#endif + + for (index = 0; index < alignment || (alignment == 0 && index < bytesPerLine); index++) { + + if (!cStyle) { + if (index == 0 && word > 0 && alignment > 0) { + *c++ = ' '; + } + + if (remain-- > 0) { + const unsigned char val = *(pos+startIndex+(index*dir)); + *c++ = makehexdigit(val>>4); + *c++ = makehexdigit(val); + } else if (!oneLine) { + *c++ = ' '; + *c++ = ' '; + } + } else { + if (remain > 0) { + if (index == 0 && word > 0) { + *c++ = ','; + *c++ = ' '; + } + if (index == 0) { + *c++ = '0'; + *c++ = 'x'; + } + const unsigned char val = *(pos+startIndex+(index*dir)); + *c++ = makehexdigit(val>>4); + *c++ = makehexdigit(val); + remain--; + } + } + } + + word += index; + } + + if (!cStyle) { + remain = length; + *c++ = ' '; + *c++ = '\''; + for (index = 0; index < bytesPerLine; index++) { + + if (remain-- > 0) { + const unsigned char val = pos[index]; + *c++ = (val >= ' ' && val < 127) ? val : '.'; + } else if (!oneLine) { + *c++ = ' '; + } + } + + *c++ = '\''; + if (length > bytesPerLine) *c++ = '\n'; + } else { + if (remain > 0) *c++ = ','; + *c++ = '\n'; + } + + if (newLine && indent) func(cookie, stringForIndent(indent)); + *c = 0; + func(cookie, buffer); + newLine = true; + + if (length <= bytesPerLine) break; + length -= bytesPerLine; + } + + if (cStyle) { + if (indent > 0) func(cookie, stringForIndent(indent-1)); + func(cookie, "};"); + } +} + +}; // namespace android + |