318 lines
8.5 KiB
C++
318 lines
8.5 KiB
C++
/*
|
|
* 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
|
|
|