| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 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 |  | 
| Mathias Agopian | 002e1e5 | 2013-05-06 20:20:50 -0700 | [diff] [blame] | 17 | #include <binder/Debug.h> | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 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 |  | 
| Colin Cross | 6f4f3ab | 2014-02-05 17:42:44 -0800 | [diff] [blame] | 41 | static void defaultPrintFunc(void* /*cookie*/, const char* txt) | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 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 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 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 |     } | 
| Dan Austin | c2bf8e8 | 2015-10-21 11:28:59 -0700 | [diff] [blame] | 141 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 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; | 
| Dan Austin | c2bf8e8 | 2015-10-21 11:28:59 -0700 | [diff] [blame] | 170 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 171 |     unsigned char *pos = (unsigned char *)buf; | 
| Dan Austin | c2bf8e8 | 2015-10-21 11:28:59 -0700 | [diff] [blame] | 172 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 173 |     if (pos == NULL) { | 
 | 174 |         if (singleLineBytesCutoff < 0) func(cookie, "\n"); | 
 | 175 |         func(cookie, "(NULL)"); | 
 | 176 |         return; | 
 | 177 |     } | 
| Dan Austin | c2bf8e8 | 2015-10-21 11:28:59 -0700 | [diff] [blame] | 178 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 179 |     if (length == 0) { | 
 | 180 |         if (singleLineBytesCutoff < 0) func(cookie, "\n"); | 
 | 181 |         func(cookie, "(empty)"); | 
 | 182 |         return; | 
 | 183 |     } | 
| Dan Austin | c2bf8e8 | 2015-10-21 11:28:59 -0700 | [diff] [blame] | 184 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 185 |     if ((int32_t)length < 0) { | 
 | 186 |         if (singleLineBytesCutoff < 0) func(cookie, "\n"); | 
 | 187 |         char buf[64]; | 
| Andrew Hsieh | 0ae8c14 | 2012-02-27 18:50:55 -0800 | [diff] [blame] | 188 |         sprintf(buf, "(bad length: %zu)", length); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 189 |         func(cookie, buf); | 
 | 190 |         return; | 
 | 191 |     } | 
| Dan Austin | c2bf8e8 | 2015-10-21 11:28:59 -0700 | [diff] [blame] | 192 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 193 |     char buffer[256]; | 
 | 194 |     static const size_t maxBytesPerLine = (sizeof(buffer)-1-11-4)/(3+1); | 
| Dan Austin | c2bf8e8 | 2015-10-21 11:28:59 -0700 | [diff] [blame] | 195 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 196 |     if (bytesPerLine > maxBytesPerLine) bytesPerLine = maxBytesPerLine; | 
| Dan Austin | c2bf8e8 | 2015-10-21 11:28:59 -0700 | [diff] [blame] | 197 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 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 |     } | 
| Dan Austin | c2bf8e8 | 2015-10-21 11:28:59 -0700 | [diff] [blame] | 208 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 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; | 
| Dan Austin | c2bf8e8 | 2015-10-21 11:28:59 -0700 | [diff] [blame] | 220 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 221 |         for (word = 0; word < bytesPerLine; ) { | 
 | 222 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 223 |             const size_t startIndex = word+(alignment-(alignment?1:0)); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 224 |  | 
 | 225 |             for (index = 0; index < alignment || (alignment == 0 && index < bytesPerLine); index++) { | 
| Dan Austin | c2bf8e8 | 2015-10-21 11:28:59 -0700 | [diff] [blame] | 226 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 227 |                 if (!cStyle) { | 
 | 228 |                     if (index == 0 && word > 0 && alignment > 0) { | 
 | 229 |                         *c++ = ' '; | 
 | 230 |                     } | 
| Dan Austin | c2bf8e8 | 2015-10-21 11:28:59 -0700 | [diff] [blame] | 231 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 232 |                     if (remain-- > 0) { | 
| Dan Austin | c2bf8e8 | 2015-10-21 11:28:59 -0700 | [diff] [blame] | 233 |                         const unsigned char val = *(pos+startIndex-index); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 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 |                         } | 
| Dan Austin | c2bf8e8 | 2015-10-21 11:28:59 -0700 | [diff] [blame] | 250 |                         const unsigned char val = *(pos+startIndex-index); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 251 |                         *c++ = makehexdigit(val>>4); | 
 | 252 |                         *c++ = makehexdigit(val); | 
 | 253 |                         remain--; | 
 | 254 |                     } | 
 | 255 |                 } | 
 | 256 |             } | 
| Dan Austin | c2bf8e8 | 2015-10-21 11:28:59 -0700 | [diff] [blame] | 257 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 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 |             } | 
| Dan Austin | c2bf8e8 | 2015-10-21 11:28:59 -0700 | [diff] [blame] | 274 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 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; | 
| Dan Austin | c2bf8e8 | 2015-10-21 11:28:59 -0700 | [diff] [blame] | 286 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 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 |  |