Home | History | Annotate | Download | only in utils
      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 
     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 inline char makeupperhexdigit(uint32_t val)
     74 {
     75     return "0123456789ABCDEF"[val&0xF];
     76 }
     77 
     78 static 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 
     87 static 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 
    103 static 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 
    163 void 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 
    171 void 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: %zu)", 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