this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

First real version of PlistBuddy (doesn't yet support Merge and Import operations)

+1047 -2
+1 -1
src/PlistBuddy/CMakeLists.txt
··· 4 4 PlistBuddy.c 5 5 ) 6 6 7 - target_link_libraries(PlistBuddy ${CoreFoundation}) 7 + target_link_libraries(PlistBuddy CoreFoundation) 8 8 9 9 install(TARGETS PlistBuddy DESTINATION libexec/darling/usr/libexec) 10 10
+1046 -1
src/PlistBuddy/PlistBuddy.c
··· 1 1 #include <stdlib.h> 2 2 #include <stdio.h> 3 3 #include <CoreFoundation/CoreFoundation.h> 4 + #include <stdbool.h> 4 5 5 - int main(int argc, char *argv[], char *envp[], char *apple[]) { 6 + bool processArgs(int argc, const char** argv, const char** command); 7 + void resolvePlistEntry(const char* whatStr, CFPropertyListRef* parent, CFPropertyListRef* entry, char** last, bool autoCreate); 8 + void setEntry(const char* entryName, const char* entryValue); 9 + void printUsage(void); 10 + void printHelp(void); 11 + bool revertToFile(void); 12 + bool saveToFile(void); 13 + void runCommand(const char* cmd); 14 + void doPrint(const char* what); 15 + 16 + enum PropertyType { 17 + typeUnknown = 0, typeString, typeArray, typeDict, typeBool, typeReal, typeInteger, typeDate, typeData 18 + }; 19 + void addEntry(const char* entry, enum PropertyType type, const char* value); 20 + CFPropertyListRef parseValue(enum PropertyType type, const char* string); 21 + void deleteEntry(const char* entry); 22 + void copyEntry(const char* src, const char* dst); 23 + 24 + // Forces XML output when printing to screen 25 + bool forceXML = false; 26 + CFPropertyListRef plist = NULL; 27 + const char* outputFile = NULL; 28 + 29 + int main(int argc, const char **argv) 30 + { 31 + const char* command = NULL; 32 + 33 + if (!processArgs(argc, argv, &command)) 34 + { 35 + printUsage(); 36 + return 1; 37 + } 38 + if (!outputFile) 39 + return 0; 40 + 41 + if (!revertToFile()) 42 + return 1; 43 + 44 + if (command != NULL) 45 + { 46 + runCommand(command); 47 + if (!saveToFile()) 48 + return 1; 49 + } 50 + else 51 + { 52 + while (true) 53 + { 54 + char buffer[200]; 55 + 56 + printf("Command: "); 57 + 58 + if (!fgets(buffer, sizeof(buffer), stdin)) 59 + break; 60 + 61 + size_t len = strlen(buffer); 62 + if (buffer[len-1] == '\n') 63 + buffer[len-1] = '\0'; 64 + runCommand(buffer); 65 + } 66 + } 67 + 6 68 return EXIT_SUCCESS; 7 69 } 70 + 71 + void printUsage() 72 + { 73 + puts("Usage: PlistBuddy [-cxh] <file.plist>\n" 74 + " -c \"<command>\" execute command, otherwise run in interactive mode\n" 75 + " -x output will be in the form of an xml plist where appropriate\n" 76 + " -h print the complete help info, with command guide\n"); 77 + } 78 + 79 + void printHelp() 80 + { 81 + puts("Command Format:\n\n" 82 + " Help - Prints this information\n" 83 + " Exit - Exits the program, changes are not saved to the file\n" 84 + " Save - Saves the current changes to the file\n" 85 + " Revert - Reloads the last saved version of the file\n" 86 + " Clear [<Type>] - Clears out all existing entries, and creates root of Type\n" 87 + " Print [<Entry>] - Prints value of Entry. Otherwise, prints file\n" 88 + " Set <Entry> <Value> - Sets the value at Entry to Value\n" 89 + " Add <Entry> <Type> [<Value>] - Adds Entry to the plist, with value Value\n" 90 + " Copy <EntrySrc> <EntryDst> - Copies the EntrySrc property to EntryDst\n" 91 + " Delete <Entry> - Deletes Entry from the plist\n" 92 + " Merge <file.plist> [<Entry>] - Adds the contents of file.plist to Entry\n" 93 + " Import <Entry> <file> - Creates or sets Entry the contents of file\n" 94 + "\n" 95 + "Entry Format:\n" 96 + " Entries consist of property key names delimited by colons. Array items\n" 97 + " are specified by a zero-based integer index. Examples:\n" 98 + " :CFBundleShortVersionString\n" 99 + " :CFBundleDocumentTypes:2:CFBundleTypeExtensions\n" 100 + "\n" 101 + "Types:\n" 102 + " string\n" 103 + " array\n" 104 + " dict\n" 105 + " bool\n" 106 + " real\n" 107 + " integer\n" 108 + " date\n" 109 + " data\n" 110 + "\n" 111 + "Examples:\n" 112 + " Set :CFBundleIdentifier com.apple.plistbuddy\n" 113 + " Sets the CFBundleIdentifier property to com.apple.plistbuddy\n" 114 + " Add :CFBundleGetInfoString string \"App version 1.0.1\"\n" 115 + " Adds the CFBundleGetInfoString property to the plist\n" 116 + " Add :CFBundleDocumentTypes: dict\n" 117 + " Adds a new item of type dict to the CFBundleDocumentTypes array\n" 118 + " Add :CFBundleDocumentTypes:0 dict\n" 119 + " Adds the new item to the beginning of the array\n" 120 + " Delete :CFBundleDocumentTypes:0 dict\n" 121 + " Deletes the FIRST item in the array\n" 122 + " Delete :CFBundleDocumentTypes\n" 123 + " Deletes the ENTIRE CFBundleDocumentTypes array\n"); 124 + } 125 + 126 + bool processArgs(int argc, const char** argv, const char** command) 127 + { 128 + if (argc <= 1) 129 + return false; 130 + 131 + for (int i = 1; i < argc; i++) 132 + { 133 + if (strcmp(argv[i], "-c") == 0) 134 + { 135 + if (i+1 >= argc) 136 + return false; 137 + *command = argv[++i]; 138 + } 139 + else if (strcmp(argv[i], "-x") == 0) 140 + { 141 + forceXML = true; 142 + } 143 + else if (strcmp(argv[i], "-h") == 0) 144 + { 145 + printHelp(); 146 + return true; 147 + } 148 + else if (i+1 >= argc) 149 + { 150 + outputFile = argv[i]; 151 + } 152 + else 153 + { 154 + puts("Invalid Arguments"); 155 + exit(1); 156 + } 157 + } 158 + 159 + return outputFile != NULL; 160 + } 161 + 162 + bool revertToFile(void) 163 + { 164 + if (plist != NULL) 165 + CFRelease(plist); 166 + 167 + if (access(outputFile, F_OK) != 0) 168 + { 169 + printf("File Doesn't Exist, Will Create: %s\n", outputFile); 170 + plist = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 171 + return true; 172 + } 173 + else 174 + { 175 + SInt32 errorCode = 0; 176 + CFStringRef errorString = NULL; 177 + CFDataRef data = NULL; 178 + CFStringRef path = CFStringCreateWithCString(kCFAllocatorDefault, outputFile, kCFStringEncodingUTF8); 179 + CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path, kCFURLPOSIXPathStyle, false); 180 + 181 + CFRelease(path); 182 + 183 + CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, url, &data, NULL, NULL, &errorCode); 184 + CFRelease(url); 185 + 186 + if (errorCode != 0) 187 + { 188 + printf("Error Reading File: %s\n", outputFile); 189 + return false; 190 + } 191 + 192 + plist = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, data, kCFPropertyListMutableContainers, &errorString); 193 + 194 + if (errorString != NULL) 195 + { 196 + CFShow(errorString); 197 + CFRelease(errorString); 198 + 199 + printf("Error Reading File: %s\n", outputFile); 200 + } 201 + 202 + return plist != NULL; 203 + } 204 + } 205 + 206 + bool saveToFile(void) 207 + { 208 + bool rv = true; 209 + CFDataRef data; 210 + CFStringRef path = CFStringCreateWithCString(kCFAllocatorDefault, outputFile, kCFStringEncodingUTF8); 211 + CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path, kCFURLPOSIXPathStyle, false); 212 + 213 + CFRelease(path); 214 + 215 + data = CFPropertyListCreateXMLData(kCFAllocatorDefault, plist); 216 + if (data != NULL) 217 + { 218 + SInt32 errorCode = 0; 219 + 220 + CFURLWriteDataAndPropertiesToResource(url, data, NULL, &errorCode); 221 + CFRelease(data); 222 + 223 + if (errorCode != 0) 224 + { 225 + puts("Cannot Write File"); 226 + rv = false; 227 + } 228 + } 229 + else 230 + { 231 + puts("Cannot Format Plist"); 232 + rv = false; 233 + } 234 + 235 + CFRelease(url); 236 + return rv; 237 + } 238 + 239 + static const char* nextWord(const char* input) 240 + { 241 + int i; 242 + 243 + for (i = 0; isspace(input[i]) && input[i] != '\0'; i++) 244 + ; 245 + 246 + if (input[i]) 247 + return &input[i]; 248 + else 249 + return NULL; 250 + } 251 + 252 + bool isCommand(const char* input, const char* cmd, const char** next) 253 + { 254 + size_t len = strlen(cmd); 255 + 256 + if (strncasecmp(input, cmd, len) == 0 && (input[len] == ' ' || input[len] == '\0')) 257 + { 258 + if (next != NULL) 259 + *next = nextWord(input + len); 260 + return true; 261 + } 262 + else 263 + return false; 264 + } 265 + 266 + static enum PropertyType parseType(const char* type) 267 + { 268 + if (strcasecmp(type, "string") == 0) 269 + return typeString; 270 + else if (strcasecmp(type, "array") == 0) 271 + return typeArray; 272 + else if (strcasecmp(type, "dict") == 0) 273 + return typeDict; 274 + else if (strcasecmp(type, "bool") == 0) 275 + return typeBool; 276 + else if (strcasecmp(type, "real") == 0) 277 + return typeReal; 278 + else if (strcasecmp(type, "integer") == 0) 279 + return typeInteger; 280 + else if (strcasecmp(type, "date") == 0) 281 + return typeDate; 282 + else if (strcasecmp(type, "data") == 0) 283 + return typeData; 284 + else 285 + { 286 + printf("Unrecognized Type: %s\n", type); 287 + return typeUnknown; 288 + } 289 + } 290 + 291 + static enum PropertyType inferType(CFPropertyListRef obj) 292 + { 293 + CFTypeID typeId = CFGetTypeID(obj); 294 + 295 + if (typeId == CFStringGetTypeID()) 296 + return typeString; 297 + else if (typeId == CFArrayGetTypeID()) 298 + return typeArray; 299 + else if (typeId == CFDictionaryGetTypeID()) 300 + return typeDict; 301 + else if (typeId == CFBooleanGetTypeID()) 302 + return typeBool; 303 + else if (typeId == CFNumberGetTypeID()) 304 + { 305 + if (CFNumberIsFloatType((CFNumberRef) obj)) 306 + return typeReal; 307 + else 308 + return typeInteger; 309 + } 310 + else if (typeId == CFDateGetTypeID()) 311 + return typeDate; 312 + else if (typeId == CFDataGetTypeID()) 313 + return typeData; 314 + else 315 + return typeUnknown; 316 + } 317 + 318 + char* getWord(const char* cmd, const char** next) 319 + { 320 + char* p = strchr(cmd, ' '); 321 + if (p == NULL) 322 + { 323 + if (next) 324 + *next = NULL; 325 + return strdup(cmd); 326 + } 327 + else 328 + { 329 + char* rv = strndup(cmd, p-cmd); 330 + if (next) 331 + *next = nextWord(p); 332 + return rv; 333 + } 334 + } 335 + 336 + void runCommand(const char* cmd) 337 + { 338 + const char* next = NULL; 339 + 340 + if (isCommand(cmd, "Exit", NULL) || isCommand(cmd, "Quit", NULL) || isCommand(cmd, "Bye", NULL)) 341 + { 342 + exit(0); 343 + } 344 + else if (isCommand(cmd, "Help", NULL)) 345 + { 346 + printHelp(); 347 + } 348 + else if (isCommand(cmd, "Save", &next)) 349 + { 350 + puts("Saving..."); 351 + saveToFile(); 352 + } 353 + else if (isCommand(cmd, "Revert", NULL)) 354 + { 355 + puts("Reverting to last saved state..."); 356 + revertToFile(); 357 + } 358 + else if (isCommand(cmd, "Print", &next) || isCommand(cmd, "ls", &next)) 359 + { 360 + doPrint(next); 361 + } 362 + else if (isCommand(cmd, "Clear", &next)) 363 + { 364 + enum PropertyType type = typeUnknown; 365 + if (next != NULL) 366 + type = parseType(next); 367 + if (type == typeUnknown) 368 + type = typeDict; 369 + } 370 + else if (isCommand(cmd, "Set", &next) || isCommand(cmd, "=", &next)) 371 + { 372 + // entry value 373 + if (!next) 374 + { 375 + puts("Missing arguments"); 376 + return; 377 + } 378 + 379 + char* entry = getWord(next, &next); 380 + 381 + if (!next) 382 + next = ""; 383 + 384 + setEntry(entry, next); 385 + 386 + free(entry); 387 + } 388 + else if (isCommand(cmd, "Add", &next) || isCommand(cmd, "+", &next)) 389 + { 390 + // entry type [value] 391 + if (!next) 392 + { 393 + puts("Missing arguments"); 394 + return; 395 + } 396 + 397 + char* entry = getWord(next, &next); 398 + 399 + if (!next) 400 + { 401 + free(entry); 402 + puts("Missing arguments"); 403 + return; 404 + } 405 + 406 + char* type = getWord(next, &next); 407 + enum PropertyType typeV = parseType(type); 408 + 409 + if (typeV == typeUnknown) 410 + { 411 + free(entry); 412 + free(type); 413 + return; 414 + } 415 + 416 + if (!next) 417 + next = ""; 418 + 419 + addEntry(entry, typeV, next); 420 + 421 + free(entry); 422 + free(type); 423 + } 424 + else if (isCommand(cmd, "Copy", &next) || isCommand(cmd, "cp", &next)) 425 + { 426 + // entrySrc entryDst 427 + if (!next) 428 + { 429 + puts("Missing arguments"); 430 + return; 431 + } 432 + 433 + char* src = getWord(next, &next); 434 + if (!next) 435 + { 436 + puts("Missing arguments"); 437 + return; 438 + } 439 + 440 + char* dst = getWord(next, NULL); 441 + 442 + copyEntry(src, dst); 443 + 444 + free(src); 445 + free(dst); 446 + } 447 + else if (isCommand(cmd, "Delete", &next) || isCommand(cmd, "rm", &next) || isCommand(cmd, "-", &next)) 448 + { 449 + // entry 450 + if (!next) 451 + { 452 + puts("Missing arguments"); 453 + return; 454 + } 455 + 456 + deleteEntry(next); 457 + } 458 + else if (isCommand(cmd, "Merge", &next)) 459 + { 460 + // file.plist [entryDst] 461 + } 462 + else if (isCommand(cmd, "Import", &next)) 463 + { 464 + // entry file.plist 465 + } 466 + else 467 + { 468 + puts("Unrecognized Command"); 469 + } 470 + } 471 + 472 + void addEntry(const char* entry, enum PropertyType type, const char* value) 473 + { 474 + CFPropertyListRef parent, existing; 475 + CFPropertyListRef newValue; 476 + char* leafName = NULL; 477 + CFTypeID parentType; 478 + 479 + // printf("add entry (type %d) with value: %s\n", type, value); 480 + 481 + if (type == typeArray) 482 + { 483 + newValue = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); 484 + } 485 + else if (type == typeDict) 486 + { 487 + newValue = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 488 + } 489 + else 490 + { 491 + newValue = parseValue(type, value); 492 + if (newValue == NULL) 493 + return; 494 + } 495 + 496 + resolvePlistEntry(entry, &parent, &existing, &leafName, true); 497 + 498 + if (parent == NULL) 499 + { 500 + printf("Add: Entry, \"%s\", Does Not Exist\n", entry); 501 + free(leafName); 502 + return; 503 + } 504 + 505 + parentType = CFGetTypeID(parent); 506 + 507 + // in case of arrays, we just insert at given position 508 + if (existing != NULL && parentType != CFArrayGetTypeID()) 509 + { 510 + printf("Add: \"%s\" Entry Already Exists\n", entry); 511 + goto out; 512 + } 513 + 514 + if (parentType == CFArrayGetTypeID()) 515 + { 516 + CFMutableArrayRef array = (CFMutableArrayRef) parent; 517 + CFIndex index = atoi(leafName); 518 + 519 + if (index < 0) 520 + index = 0; 521 + else if (index > CFArrayGetCount(array)) 522 + index = CFArrayGetCount(array); 523 + 524 + CFArrayInsertValueAtIndex(array, index, newValue); 525 + } 526 + else if (parentType == CFDictionaryGetTypeID()) 527 + { 528 + // printf("Add new entry named %s into dict %p, root is %p\n", leafName, parent, plist); 529 + CFStringRef key = CFStringCreateWithCString(kCFAllocatorDefault, leafName, kCFStringEncodingUTF8); 530 + CFDictionaryAddValue((CFMutableDictionaryRef) parent, key, newValue); 531 + CFRelease(key); 532 + } 533 + else 534 + { 535 + printf("Add: Can't Add Entry, \"%s\", to Parent\n", entry); 536 + } 537 + 538 + out: 539 + free(leafName); 540 + CFRelease(newValue); 541 + } 542 + 543 + CFPropertyListRef parseValue(enum PropertyType type, const char* string) 544 + { 545 + switch (type) 546 + { 547 + case typeString: 548 + case typeData: 549 + { 550 + char* stringOut; 551 + bool hasQuotes = string[0] == '"'; 552 + 553 + size_t len = strlen(string); 554 + size_t i = 0, j = 0; 555 + 556 + if (hasQuotes) 557 + { 558 + if (string[len-1] != '"') 559 + { 560 + puts("Parse Error: Unclosed Quotes"); 561 + return NULL; 562 + } 563 + i++; 564 + len--; 565 + } 566 + 567 + stringOut = (char*) malloc(len+1); 568 + 569 + for (; i < len; i++) 570 + { 571 + if (string[i] != '\\') 572 + { 573 + stringOut[j] = string[i]; 574 + j++; 575 + } 576 + else 577 + { 578 + if (i+1 == len) 579 + { 580 + free(stringOut); 581 + puts("Parse Error: Unclosed Quotes"); 582 + return NULL; 583 + } 584 + 585 + switch (string[++i]) 586 + { 587 + case '"': 588 + stringOut[j++] = '"'; 589 + break; 590 + case 'n': 591 + stringOut[j++] = '\n'; 592 + break; 593 + case 't': 594 + stringOut[j++] = '\t'; 595 + break; 596 + default: 597 + stringOut[j++] = string[i]; 598 + } 599 + } 600 + } 601 + stringOut[j] = '\0'; 602 + 603 + CFPropertyListRef rv; 604 + if (type == typeString) 605 + rv = CFStringCreateWithCString(kCFAllocatorDefault, stringOut, kCFStringEncodingUTF8); 606 + else 607 + rv = CFDataCreate(kCFAllocatorDefault, (const UInt8*) string, strlen(string)); 608 + 609 + free(stringOut); 610 + return rv; 611 + } 612 + case typeBool: 613 + if (strcasecmp(string, "true") == 0 || strcasecmp(string, "yes") == 0 || strcmp(string, "1") == 0) 614 + return kCFBooleanTrue; 615 + return kCFBooleanFalse; 616 + 617 + case typeInteger: 618 + { 619 + char* endptr; 620 + long long v; 621 + 622 + v = strtoll(string, &endptr, 0); 623 + if (endptr == string) 624 + { 625 + puts("Unrecognized Integer Format"); 626 + return NULL; 627 + } 628 + 629 + return CFNumberCreate(kCFAllocatorDefault, kCFNumberLongLongType, &v); 630 + } 631 + 632 + case typeReal: 633 + { 634 + char* endptr; 635 + double v; 636 + 637 + v = strtod(string, &endptr); 638 + if (endptr == string) 639 + { 640 + puts("Unrecognized Real Format"); 641 + return NULL; 642 + } 643 + 644 + return CFNumberCreate(kCFAllocatorDefault, kCFNumberFloat64Type, &v); 645 + } 646 + case typeDate: 647 + { 648 + struct tm tm; 649 + 650 + if (!strptime(string, "%a %b %d %H:%M:%S %Z %Y", &tm) 651 + && !strptime(string, "%c", &tm) 652 + && !strptime(string, "%D", &tm)) 653 + { 654 + puts("Unrecognized Date Format"); 655 + return NULL; 656 + } 657 + 658 + CFTimeZoneRef tz = CFTimeZoneCopyDefault(); 659 + CFAbsoluteTime at; 660 + CFGregorianDate date; 661 + 662 + date.day = tm.tm_mday; 663 + date.hour = tm.tm_hour; 664 + date.minute = tm.tm_min; 665 + date.month = tm.tm_mon + 1; 666 + date.second = tm.tm_sec; 667 + date.year = tm.tm_year + 1900; 668 + 669 + at = CFGregorianDateGetAbsoluteTime(date, tz); 670 + 671 + CFDateRef rv = CFDateCreate(kCFAllocatorDefault, at); 672 + 673 + CFRelease(tz); 674 + return rv; 675 + } 676 + default: 677 + { 678 + puts("Cannot parse this entry type"); 679 + return NULL; 680 + } 681 + } 682 + } 683 + 684 + void setEntry(const char* entry, const char* entryValue) 685 + { 686 + CFPropertyListRef parent, existing; 687 + CFPropertyListRef newValue; 688 + char* leafName = NULL; 689 + enum PropertyType type; 690 + 691 + resolvePlistEntry(entry, &parent, &existing, &leafName, false); 692 + if (existing == NULL) 693 + { 694 + free(leafName); 695 + printf("Set: Entry, \"%s\", Does Not Exist\n", entry); 696 + return; 697 + } 698 + 699 + type = inferType(existing); 700 + if (type == typeArray || type == typeDict) 701 + { 702 + free(leafName); 703 + puts("Set: Cannot Perform Set On Containers"); 704 + return; 705 + } 706 + 707 + newValue = parseValue(type, entryValue); 708 + if (newValue == NULL) 709 + { 710 + free(leafName); 711 + return; 712 + } 713 + 714 + if (CFGetTypeID(parent) == CFDictionaryGetTypeID()) 715 + { 716 + CFStringRef leafNameStr = CFStringCreateWithCString(kCFAllocatorDefault, leafName, kCFStringEncodingUTF8); 717 + CFDictionaryReplaceValue((CFMutableDictionaryRef) parent, leafNameStr, newValue); 718 + CFRelease(leafNameStr); 719 + } 720 + else 721 + { 722 + int index = atoi(leafName); 723 + 724 + CFArraySetValueAtIndex((CFMutableArrayRef) parent, index, newValue); 725 + } 726 + 727 + free(leafName); 728 + CFRelease(newValue); 729 + } 730 + 731 + char* strtok_empty(char* str, char delim) 732 + { 733 + static char* src = NULL; 734 + char* p, *ret = NULL; 735 + 736 + if (str != NULL) 737 + src = str; 738 + 739 + if (src == NULL) 740 + return NULL; 741 + 742 + if ((p = strchr (src, delim)) != NULL) 743 + { 744 + *p = '\0'; 745 + ret = src; 746 + src = ++p; 747 + } 748 + else 749 + { 750 + ret = src; 751 + src = NULL; 752 + } 753 + 754 + return ret; 755 + } 756 + 757 + void resolvePlistEntry(const char* whatStr, CFPropertyListRef* parent, CFPropertyListRef* entry, char** last, bool autoCreate) 758 + { 759 + CFPropertyListRef pos = plist; 760 + CFPropertyListRef lastPos = NULL; 761 + 762 + const char *tok, *lastTok = ""; 763 + 764 + if (whatStr[0] == ':') 765 + whatStr++; 766 + 767 + char* whatStr2 = strdup(whatStr); 768 + const char* finalTok = strrchr(whatStr2, ':'); 769 + 770 + if (finalTok == NULL) 771 + finalTok = whatStr2; 772 + else 773 + finalTok++; 774 + 775 + if (*whatStr2) 776 + tok = strtok_empty(whatStr2, ':'); 777 + else 778 + tok = NULL; 779 + 780 + while (tok != NULL && pos != NULL) 781 + { 782 + lastPos = pos; 783 + if (*tok) 784 + { 785 + CFTypeID typeId = CFGetTypeID(pos); 786 + 787 + if (typeId == CFDictionaryGetTypeID()) 788 + { 789 + CFStringRef key = CFStringCreateWithCString(kCFAllocatorDefault, tok, kCFStringEncodingUTF8); 790 + pos = (CFPropertyListRef) CFDictionaryGetValue((CFDictionaryRef) pos, key); 791 + 792 + if (pos == NULL && autoCreate && tok != finalTok) 793 + { 794 + pos = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 795 + CFDictionaryAddValue((CFMutableDictionaryRef) lastPos, key, pos); 796 + } 797 + CFRelease(key); 798 + } 799 + else if (typeId == CFArrayGetTypeID()) 800 + { 801 + int index = atoi(tok); 802 + if (index < 0 || index >= CFArrayGetCount((CFArrayRef) pos)) 803 + { 804 + pos = NULL; 805 + } 806 + else 807 + { 808 + pos = (CFPropertyListRef) CFArrayGetValueAtIndex((CFArrayRef) pos, index); 809 + } 810 + } 811 + else 812 + { 813 + pos = NULL; 814 + } 815 + } 816 + else 817 + pos = NULL; 818 + 819 + lastTok = tok; 820 + tok = strtok_empty(NULL, ':'); 821 + } 822 + 823 + if (last != NULL) 824 + *last = strdup(lastTok); 825 + 826 + if (entry != NULL) 827 + *entry = pos; 828 + 829 + if (parent != NULL) 830 + *parent = (!tok) ? lastPos : NULL; 831 + 832 + free(whatStr2); 833 + } 834 + 835 + void prettyPrintPlist(CFPropertyListRef what, int indentNum) 836 + { 837 + CFTypeID typeId = CFGetTypeID(what); 838 + char* indent = __builtin_alloca(indentNum + 1); 839 + 840 + memset(indent, ' ', indentNum); 841 + indent[indentNum] = '\0'; 842 + 843 + if (typeId == CFStringGetTypeID()) 844 + { 845 + const char* str = CFStringGetCStringPtr((CFStringRef) what, kCFStringEncodingUTF8); 846 + printf("%s", str); 847 + } 848 + else if (typeId == CFArrayGetTypeID()) 849 + { 850 + CFArrayRef array = (CFArrayRef) what; 851 + CFIndex count = CFArrayGetCount(array); 852 + 853 + printf("Array {\n"); 854 + for (CFIndex i = 0; i < count; i++) 855 + { 856 + CFPropertyListRef elem = (CFPropertyListRef) CFArrayGetValueAtIndex(array, i); 857 + printf("%s ", indent); 858 + 859 + prettyPrintPlist(elem, indentNum + 4); 860 + printf("\n"); 861 + } 862 + 863 + printf("%s}\n", indent); 864 + } 865 + else if (typeId == CFDictionaryGetTypeID()) 866 + { 867 + CFDictionaryRef dict = (CFDictionaryRef) what; 868 + CFStringRef* keys; 869 + CFPropertyListRef* values; 870 + 871 + CFIndex count = CFDictionaryGetCount(dict); 872 + 873 + keys = malloc(sizeof(CFStringRef*) * count); 874 + values = malloc(sizeof(CFStringRef*) * count); 875 + 876 + CFDictionaryGetKeysAndValues(dict, (const void**) keys, (const void**) values); 877 + 878 + printf("Dict {\n"); 879 + for (CFIndex i = 0; i < count; i++) 880 + { 881 + printf("%s ", indent); 882 + prettyPrintPlist(keys[i], 0); 883 + printf(" = "); 884 + prettyPrintPlist(values[i], indentNum + 4); 885 + printf("\n"); 886 + } 887 + 888 + printf("%s}\n", indent); 889 + 890 + free(keys); 891 + free(values); 892 + } 893 + else if (typeId == CFBooleanGetTypeID()) 894 + { 895 + if (what == kCFBooleanTrue) 896 + printf("true"); 897 + else 898 + printf("false"); 899 + } 900 + else if (typeId == CFNumberGetTypeID()) 901 + { 902 + CFNumberRef num = (CFNumberRef) what; 903 + 904 + if (CFNumberIsFloatType(num)) 905 + { 906 + Float64 d; 907 + CFNumberGetValue(num, kCFNumberFloat64Type, &d); 908 + printf("%f", d); 909 + } 910 + else 911 + { 912 + long long l; 913 + CFNumberGetValue(num, kCFNumberLongLongType, &l); 914 + printf("%lld", l); 915 + } 916 + } 917 + else if (typeId == CFDateGetTypeID()) 918 + { 919 + CFAbsoluteTime t = CFDateGetAbsoluteTime((CFDateRef) what); 920 + CFTimeZoneRef tz = CFTimeZoneCopyDefault(); 921 + CFGregorianDate d = CFAbsoluteTimeGetGregorianDate(t, tz); 922 + struct tm tm; 923 + char buf[150]; 924 + 925 + tm.tm_mday = d.day; 926 + tm.tm_mon = d.month - 1; 927 + tm.tm_year = d.year - 1900; 928 + tm.tm_hour = d.hour; 929 + tm.tm_min = d.minute; 930 + tm.tm_sec = d.second; 931 + tm.tm_wday = CFAbsoluteTimeGetDayOfWeek(t, tz); 932 + 933 + if (tm.tm_wday == 7) 934 + tm.tm_wday = 0; 935 + 936 + tm.tm_zone = 0; 937 + tm.tm_isdst = 0; 938 + 939 + strftime(buf, sizeof(buf), "%a %b %d %H:%M:%S %Z %Y", &tm); 940 + printf("%s", buf); 941 + 942 + CFRelease(tz); 943 + } 944 + else if (typeId == CFDataGetTypeID()) 945 + { 946 + CFDataRef data = (CFDataRef) what; 947 + const UInt8* bytes = CFDataGetBytePtr(data); 948 + CFIndex len = CFDataGetLength(data); 949 + 950 + fwrite(bytes, 1, len, stdout); 951 + putchar('\n'); 952 + } 953 + } 954 + 955 + void doPrint(const char* whatStr) 956 + { 957 + CFPropertyListRef what = plist; 958 + 959 + if (whatStr != NULL) 960 + { 961 + resolvePlistEntry(whatStr, &what, NULL, NULL, false); 962 + if (what == NULL) 963 + { 964 + printf("Print: Entry, \"%s\", Does Not Exist\n", whatStr); 965 + return; 966 + } 967 + } 968 + 969 + if (!forceXML) 970 + prettyPrintPlist(what, 0); 971 + else 972 + { 973 + CFDataRef data = CFPropertyListCreateXMLData(kCFAllocatorDefault, plist); 974 + 975 + if (data != NULL) 976 + { 977 + prettyPrintPlist(data, 0); 978 + 979 + CFRelease(data); 980 + } 981 + } 982 + } 983 + 984 + void deleteEntry(const char* entry) 985 + { 986 + CFPropertyListRef parent, existing; 987 + CFPropertyListRef newValue; 988 + char* leafName = NULL; 989 + 990 + resolvePlistEntry(entry, &parent, &existing, &leafName, false); 991 + if (existing == NULL) 992 + { 993 + printf("Delete: Entry, \"%s\", Does Not Exist\n", entry); 994 + goto out; 995 + } 996 + 997 + CFTypeID typeID = CFGetTypeID(parent); 998 + if (typeID == CFDictionaryGetTypeID()) 999 + { 1000 + CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, leafName, kCFStringEncodingUTF8); 1001 + CFDictionaryRemoveValue((CFMutableDictionaryRef) parent, str); 1002 + CFRelease(str); 1003 + } 1004 + else 1005 + { 1006 + CFIndex idx = atoi(leafName); 1007 + CFArrayRemoveValueAtIndex((CFMutableArrayRef) parent, idx); 1008 + } 1009 + 1010 + out: 1011 + free(leafName); 1012 + } 1013 + 1014 + void copyEntry(const char* src, const char* dst) 1015 + { 1016 + CFPropertyListRef existing, entry, newParent, entryCopy; 1017 + char* leafName = NULL; 1018 + 1019 + resolvePlistEntry(src, NULL, &entry, NULL, false); 1020 + resolvePlistEntry(dst, &newParent, &existing, &leafName, true); 1021 + 1022 + if (entry == NULL) 1023 + { 1024 + printf("Copy: Entry, \"%s\", Does Not Exist\n", src); 1025 + goto out; 1026 + } 1027 + if (existing != NULL) 1028 + { 1029 + printf("Copy: \"%s\" Entry Already Exists\n", dst); 1030 + goto out; 1031 + } 1032 + 1033 + entryCopy = CFPropertyListCreateDeepCopy(kCFAllocatorDefault, entry, kCFPropertyListMutableContainers); 1034 + 1035 + CFTypeID typeID = CFGetTypeID(newParent); 1036 + if (typeID == CFDictionaryGetTypeID()) 1037 + { 1038 + CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, leafName, kCFStringEncodingUTF8); 1039 + CFDictionaryAddValue((CFMutableDictionaryRef) newParent, str, entryCopy); 1040 + CFRelease(str); 1041 + } 1042 + else 1043 + { 1044 + CFIndex idx = atoi(leafName); 1045 + CFArrayInsertValueAtIndex((CFMutableArrayRef) newParent, idx, entryCopy); 1046 + } 1047 + 1048 + CFRelease(entryCopy); 1049 + out: 1050 + free(leafName); 1051 + } 1052 +