1 /* 2 * Copyright 2004-2009, Axel Dörfler, axeld@pinc-software.de. 3 * Copyright 2002, Ryan Fleet. 4 * 5 * Distributed under the terms of the MIT license. 6 */ 7 8 9 #include <String.h> 10 #include <TypeConstants.h> 11 #include <Mime.h> 12 13 #include <fs_attr.h> 14 15 #include <ctype.h> 16 #include <string.h> 17 #include <stdio.h> 18 19 20 /*! Dumps the contents of the attribute in the form of raw data. This view 21 is used for the type B_RAW_TYPE, for custom types and for any type that 22 is not directly supported by the utility "addattr". 23 */ 24 static void 25 dump_raw_data(const char *buffer, size_t size) 26 { 27 const uint32 kChunkSize = 16; 28 uint32 dumpPosition = 0; 29 30 while (dumpPosition < size) { 31 // Position for this line 32 printf("\t%04lx: ", dumpPosition); 33 34 // Print the bytes in form of hexadecimal numbers 35 for (uint32 i = 0; i < kChunkSize; i++) { 36 if (dumpPosition + i < size) { 37 printf("%02x ", (uint8)buffer[dumpPosition + i]); 38 } else 39 printf(" "); 40 } 41 42 // Print the bytes in form of printable characters 43 // (whenever possible) 44 printf(" "); 45 for (uint32 i = 0; i < kChunkSize; i++) { 46 if (dumpPosition < size) { 47 char c = buffer[dumpPosition]; 48 putchar(isgraph(c) ? c : '.'); 49 } else 50 putchar(' '); 51 52 dumpPosition++; 53 } 54 printf("\n"); 55 } 56 } 57 58 59 static void 60 show_attr_contents(BNode& node, const char* attribute, const attr_info& info) 61 { 62 // limit size of the attribute, only the first kLimit byte will make it on 63 // screen 64 int kLimit = 256; 65 bool cut = false; 66 off_t size = info.size; 67 if (size > kLimit) { 68 size = kLimit; 69 cut = true; 70 } 71 72 char buffer[kLimit]; 73 ssize_t bytesRead = node.ReadAttr(attribute, info.type, 0, buffer, size); 74 if (bytesRead != size) { 75 fprintf(stderr, "Could only read %lld bytes from attribute!\n", 76 size); 77 return; 78 } 79 80 switch (info.type) { 81 case B_INT8_TYPE: 82 printf("%d\n", *((int8 *)buffer)); 83 break; 84 case B_UINT8_TYPE: 85 printf("%u\n", *((uint8 *)buffer)); 86 break; 87 case B_INT16_TYPE: 88 printf("%d\n", *((int16 *)buffer)); 89 break; 90 case B_UINT16_TYPE: 91 printf("%u\n", *((uint16 *)buffer)); 92 break; 93 case B_INT32_TYPE: 94 printf("%ld\n", *((int32 *)buffer)); 95 break; 96 case B_UINT32_TYPE: 97 printf("%lu\n", *((uint32 *)buffer)); 98 break; 99 case B_INT64_TYPE: 100 printf("%lld\n", *((int64 *)buffer)); 101 break; 102 case B_UINT64_TYPE: 103 printf("%llu\n", *((uint64 *)buffer)); 104 break; 105 case B_FLOAT_TYPE: 106 printf("%f\n", *((float *)buffer)); 107 break; 108 case B_DOUBLE_TYPE: 109 printf("%f\n", *((double *)buffer)); 110 break; 111 case B_BOOL_TYPE: 112 printf("%d\n", *((unsigned char *)buffer)); 113 break; 114 case B_STRING_TYPE: 115 case B_MIME_STRING_TYPE: 116 case 'MSIG': 117 case 'MSDC': 118 case 'MPTH': 119 printf("%s\n", buffer); 120 break; 121 122 case B_MESSAGE_TYPE: 123 { 124 BMessage message; 125 if (!cut && message.Unflatten(buffer) == B_OK) { 126 putchar('\n'); 127 message.PrintToStream(); 128 putchar('\n'); 129 break; 130 } 131 // supposed to fall through 132 } 133 134 default: 135 // The rest of the attributes types are displayed as raw data 136 putchar('\n'); 137 dump_raw_data(buffer, size); 138 putchar('\n'); 139 break; 140 } 141 } 142 143 144 static const char * 145 get_type(type_code type) 146 { 147 static char buffer[32]; 148 149 switch (type) { 150 case B_MIME_STRING_TYPE: 151 return "MIME String"; 152 case B_RAW_TYPE: 153 return "Raw Data"; 154 155 case B_STRING_TYPE: 156 return "Text"; 157 case B_INT64_TYPE: 158 return "Int-64"; 159 case B_UINT64_TYPE: 160 return "Uint-64"; 161 case B_INT32_TYPE: 162 return "Int-32"; 163 case B_UINT32_TYPE: 164 return "Uint-32"; 165 case B_INT16_TYPE: 166 return "Int-16"; 167 case B_UINT16_TYPE: 168 return "Uint-16"; 169 case B_INT8_TYPE: 170 return "Int-8"; 171 case B_UINT8_TYPE: 172 return "Uint-8"; 173 case B_BOOL_TYPE: 174 return "Boolean"; 175 case B_FLOAT_TYPE: 176 return "Float"; 177 case B_DOUBLE_TYPE: 178 return "Double"; 179 180 case B_MINI_ICON_TYPE: 181 return "Mini Icon"; 182 case B_LARGE_ICON_TYPE: 183 return "Icon"; 184 185 default: 186 { 187 int32 missed = 0, shift = 24; 188 uint8 value[4]; 189 for (int32 i = 0; i < 4; i++, shift -= 8) { 190 value[i] = uint8(type >> shift); 191 if (value[i] < ' ' || value[i] > 127) { 192 value[i] = '.'; 193 missed++; 194 } 195 } 196 197 if (missed < 2) { 198 sprintf(buffer, "'%c%c%c%c'", value[0], value[1], value[2], 199 value[3]); 200 } else 201 sprintf(buffer, "0x%08lx", type); 202 203 return buffer; 204 } 205 } 206 } 207 208 209 int 210 main(int argc, char *argv[]) 211 { 212 const char *program = strrchr(argv[0], '/'); 213 if (program == NULL) 214 program = argv[0]; 215 else 216 program++; 217 218 bool printContents = false; 219 220 if (argc > 2 && (!strcmp(argv[1], "--long") || !strcmp(argv[1], "-l"))) { 221 printContents = true; 222 argc--; 223 argv++; 224 } 225 226 if (argc < 2 || !strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")) { 227 printf("usage: %s [-l|--long] 'filename' ['filename' ...]\n" 228 " -l, --long Shows the attribute contents as well.\n", program); 229 return argc == 2 ? 0 : 1; 230 } 231 232 off_t total = 0; 233 234 for (int i = 1; i < argc; ++i) { 235 BNode node(argv[i]); 236 237 status_t status = node.InitCheck(); 238 if (status < B_OK) { 239 fprintf(stderr, "%s: initialization failed for \"%s\": %s\n", 240 program, argv[i], strerror(status)); 241 return 0; 242 } 243 244 printf("File: %s\n", argv[i]); 245 246 const int kTypeWidth = 12; 247 const int kSizeWidth = 10; 248 const int kNameWidth = 36; 249 const int kContentsWidth = 21; 250 printf("%*s %*s %-*s%s\n", kTypeWidth, "Type", kSizeWidth, "Size", 251 kNameWidth, "Name", printContents ? "Contents" : ""); 252 253 BString separator; 254 separator.SetTo('-', kTypeWidth + kSizeWidth + kNameWidth 255 + (printContents ? kContentsWidth : 0)); 256 puts(separator.String()); 257 258 char name[B_ATTR_NAME_LENGTH]; 259 while (node.GetNextAttrName(name) == B_OK) { 260 attr_info attrInfo; 261 262 status = node.GetAttrInfo(name, &attrInfo); 263 if (status >= B_OK) { 264 printf("%*s", kTypeWidth, get_type(attrInfo.type)); 265 printf("% *Li ", kSizeWidth, attrInfo.size); 266 printf("\"%s\"", name); 267 268 if (printContents) { 269 // padding 270 int length = kNameWidth - 2 - strlen(name); 271 if (length > 0) 272 printf("%*s", length, ""); 273 274 show_attr_contents(node, name, attrInfo); 275 } else 276 putchar('\n'); 277 278 total += attrInfo.size; 279 } else { 280 fprintf(stderr, "%s: stat failed for \"%s\": %s\n", 281 program, name, strerror(status)); 282 } 283 } 284 } 285 286 printf("\n%Ld bytes total in attributes.\n", total); 287 return 0; 288 } 289