| 759 | | else { |
|---|
| 760 | | static LSItemInfoRecord info; |
|---|
| 761 | | CFStringRef version = NULL; |
|---|
| 762 | | UInt32 intVersion = 0; |
|---|
| 763 | | OSStatus err = LSCopyItemInfoForURL(url, kLSRequestAllInfo, &info); |
|---|
| 764 | | Boolean haveFSRef; |
|---|
| 765 | | FSRef fsr; |
|---|
| 766 | | if (err != noErr) osstatusexit(err, "unable to get information about '%s'", strBuffer); |
|---|
| 767 | | haveFSRef = CFURLGetFSRef(url, &fsr); |
|---|
| 768 | | |
|---|
| 769 | | printf("%s: ", strBuffer); |
|---|
| 770 | | |
|---|
| 771 | | // modifiers |
|---|
| 772 | | if (info.flags & kLSItemInfoIsInvisible) printf("invisible "); |
|---|
| 773 | | if (info.flags & kLSItemInfoAppIsScriptable) printf("scriptable "); |
|---|
| 774 | | if (info.flags & kLSItemInfoIsNativeApp) printf("Mac OS X "); |
|---|
| 775 | | if (info.flags & kLSItemInfoIsClassicApp) printf("Classic "); |
|---|
| 776 | | |
|---|
| 777 | | // kind |
|---|
| 778 | | if (info.flags & kLSItemInfoIsVolume) printf("volume"); |
|---|
| 779 | | else if (info.flags & kLSItemInfoIsApplication) printf("application "); |
|---|
| 780 | | else if (info.flags & kLSItemInfoIsPackage) printf("non-application "); |
|---|
| 781 | | else if (info.flags & kLSItemInfoIsContainer) printf("folder"); |
|---|
| 782 | | else if (info.flags & kLSItemInfoIsAliasFile) printf("alias"); |
|---|
| 783 | | else if (info.flags & kLSItemInfoIsSymlink) printf("symbolic link"); |
|---|
| 784 | | else if (info.flags & kLSItemInfoIsPlainFile) printf("document"); |
|---|
| 785 | | else printf("unknown file system entity"); |
|---|
| 786 | | |
|---|
| 787 | | if (info.flags & kLSItemInfoIsPackage) printf("package "); |
|---|
| 788 | | |
|---|
| 789 | | if (info.flags & kLSItemInfoAppPrefersNative) printf("[Carbon, prefers native OS X]"); |
|---|
| 790 | | else if (info.flags & kLSItemInfoAppPrefersClassic) printf("[Carbon, prefers Classic]"); |
|---|
| 791 | | |
|---|
| 792 | | printf("\n"); |
|---|
| 793 | | if (!(info.flags & kLSItemInfoIsContainer) || info.flags & kLSItemInfoIsPackage) { |
|---|
| 794 | | printf("\ttype: '%s'", utf8StringFromOSType(info.filetype)); |
|---|
| 795 | | printf("\tcreator: '%s'\n", utf8StringFromOSType(info.creator)); |
|---|
| 796 | | } |
|---|
| 797 | | if (info.flags & kLSItemInfoIsPackage || info.flags & kLSItemInfoIsApplication) { |
|---|
| 798 | | // a package, or possibly a native app with a 'plst' resource |
|---|
| 799 | | CFBundleRef bundle = CFBundleCreate(NULL, url); |
|---|
| 800 | | CFStringRef bundleID = NULL; |
|---|
| 801 | | if (bundle == NULL && (info.flags & kLSItemInfoIsApplication)) { |
|---|
| 802 | | if (info.flags & kLSItemInfoIsPackage || !haveFSRef) { |
|---|
| 803 | | printf("\t[can't access CFBundle for application]\n"); |
|---|
| 804 | | } else { // OS X bug causes this to fail when it shouldn't, so fake it |
|---|
| 805 | | SInt16 resFork = FSOpenResFile(&fsr, fsRdPerm); |
|---|
| 806 | | OSStatus err = ResError(); |
|---|
| 807 | | if (err != noErr) { |
|---|
| 808 | | printf("\t[can't open resource fork: %s]\n", osstatusstr(err)); |
|---|
| 809 | | } else { |
|---|
| 810 | | Handle h = Get1Resource('plst', 0); |
|---|
| 811 | | if ( (err = ResError()) != noErr || h == NULL) { |
|---|
| 812 | | if (err != noErr && err != resNotFound) osstatusexit(err, "unable to read 'plst' 0 resource"); |
|---|
| 813 | | } else { |
|---|
| 814 | | CFDataRef plstData = CFDataCreate(NULL, (UInt8 *)*h, GetHandleSize(h)); |
|---|
| 815 | | CFStringRef error; |
|---|
| 816 | | CFPropertyListRef infoPlist = CFPropertyListCreateFromXMLData(NULL, plstData, kCFPropertyListImmutable, &error); |
|---|
| 817 | | if (plstData != NULL) { |
|---|
| 818 | | CFRelease(plstData); |
|---|
| 819 | | plstData = NULL; |
|---|
| 820 | | } else { |
|---|
| 821 | | // this function should handle the 'plst' 0 case too, but it doesn't provide error messages; however, it handles the case of an unbundled Mach-O binary, so it is useful as a fallback |
|---|
| 822 | | infoPlist = CFBundleCopyInfoDictionaryForURL(url); |
|---|
| 823 | | } |
|---|
| 824 | | if (infoPlist == NULL) { |
|---|
| 825 | | printf("\t['plst' 0 resource invalid: %s]\n", utf8StringFromCFStringRef(error)); |
|---|
| 826 | | CFRelease(error); |
|---|
| 827 | | } else { |
|---|
| 828 | | // mimic CFBundle logic below |
|---|
| 829 | | bundleID = CFDictionaryGetValue(infoPlist, kCFBundleIdentifierKey); |
|---|
| 830 | | if (bundleID != NULL) CFRetain(bundleID); |
|---|
| 831 | | version = CFDictionaryGetValue(infoPlist, CFSTR("CFBundleShortVersionString")); |
|---|
| 832 | | if (version == NULL) |
|---|
| 833 | | version = CFDictionaryGetValue(infoPlist, kCFBundleVersionKey); |
|---|
| 834 | | if (version != NULL) CFRetain(version); |
|---|
| 835 | | CFRelease(infoPlist); |
|---|
| 836 | | } |
|---|
| 837 | | } |
|---|
| 838 | | VersRecHndl vers = (VersRecHndl)Get1Resource('vers', 1); |
|---|
| 839 | | if ( (err = ResError()) != noErr || vers == NULL) { |
|---|
| 840 | | if (err != noErr && err != resNotFound) osstatusexit(err, "unable to read 'vers' 1 resource"); |
|---|
| 841 | | } else { |
|---|
| 842 | | if (version == NULL) { // prefer 'plst' version |
|---|
| 843 | | version = CFStringCreateWithPascalString(NULL, vers[0]->shortVersion, CFStringGetSystemEncoding()); // XXX use country code instead? |
|---|
| 844 | | } |
|---|
| 845 | | intVersion = ((NumVersionVariant)vers[0]->numericVersion).whole; |
|---|
| 846 | | } |
|---|
| 847 | | CloseResFile(resFork); |
|---|
| 848 | | } |
|---|
| 849 | | } |
|---|
| 850 | | } else { |
|---|
| 851 | | bundleID = CFBundleGetIdentifier(bundle); |
|---|
| 852 | | if (bundleID != NULL) CFRetain(bundleID); |
|---|
| 853 | | // prefer a short version string, e.g. "1.0 Beta" instead of "51" for Safari |
|---|
| 854 | | version = CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("CFBundleShortVersionString")); |
|---|
| 855 | | if (version == NULL) |
|---|
| 856 | | version = CFBundleGetValueForInfoDictionaryKey(bundle, kCFBundleVersionKey); |
|---|
| 857 | | if (version != NULL) { |
|---|
| 858 | | CFRetain(version); |
|---|
| 859 | | intVersion = CFBundleGetVersionNumber(bundle); |
|---|
| 860 | | } |
|---|
| 861 | | CFURLRef executable = CFBundleCopyExecutableURL(bundle); |
|---|
| 862 | | if (executable != NULL) { |
|---|
| 863 | | printExecutableArchitectures(executable, true); |
|---|
| 864 | | CFRelease(executable); |
|---|
| 865 | | } |
|---|
| 866 | | CFRelease(bundle); |
|---|
| 867 | | } |
|---|
| 868 | | if (bundleID != NULL) { |
|---|
| 869 | | printf("\tbundle ID: %s\n", utf8StringFromCFStringRef(bundleID)); |
|---|
| 870 | | CFRelease(bundleID); |
|---|
| 871 | | } |
|---|
| 872 | | } else { |
|---|
| 873 | | printExecutableArchitectures(url, false); |
|---|
| 874 | | if (haveFSRef) { |
|---|
| 875 | | // try to get a version if we can, but don't complain if we can't |
|---|
| 876 | | SInt16 resFork = FSOpenResFile(&fsr, fsRdPerm); |
|---|
| 877 | | if (ResError() == noErr) { |
|---|
| 878 | | VersRecHndl vers = (VersRecHndl)Get1Resource('vers', 1); |
|---|
| 879 | | if (ResError() == noErr && vers != NULL) { |
|---|
| 880 | | version = CFStringCreateWithPascalString(NULL, vers[0]->shortVersion, CFStringGetSystemEncoding()); // XXX use country code instead? |
|---|
| 881 | | intVersion = ((NumVersionVariant)vers[0]->numericVersion).whole; |
|---|
| 882 | | } |
|---|
| 883 | | } |
|---|
| 884 | | CloseResFile(resFork); |
|---|
| 885 | | } |
|---|
| 886 | | } |
|---|
| 887 | | |
|---|
| | 760 | return; |
|---|
| | 761 | } |
|---|
| | 762 | |
|---|
| | 763 | static LSItemInfoRecord info; |
|---|
| | 764 | OSStatus err; |
|---|
| | 765 | if ( (err = LSCopyItemInfoForURL(url, kLSRequestAllInfo, &info)) != noErr) |
|---|
| | 766 | osstatusexit(err, "unable to get information about '%s'", strBuffer); |
|---|
| | 767 | |
|---|
| | 768 | printf("%s: ", strBuffer); |
|---|
| | 769 | |
|---|
| | 770 | // modifiers |
|---|
| | 771 | if (info.flags & kLSItemInfoIsInvisible) printf("invisible "); |
|---|
| | 772 | if (info.flags & kLSItemInfoAppIsScriptable) printf("scriptable "); |
|---|
| | 773 | if (info.flags & kLSItemInfoIsNativeApp) printf("Mac OS X "); |
|---|
| | 774 | if (info.flags & kLSItemInfoIsClassicApp) printf("Classic "); |
|---|
| | 775 | |
|---|
| | 776 | // kind |
|---|
| | 777 | if (info.flags & kLSItemInfoIsVolume) printf("volume"); |
|---|
| | 778 | else if (info.flags & kLSItemInfoIsApplication) printf("application "); |
|---|
| | 779 | else if (info.flags & kLSItemInfoIsPackage) printf("non-application "); |
|---|
| | 780 | else if (info.flags & kLSItemInfoIsContainer) printf("folder"); |
|---|
| | 781 | else if (info.flags & kLSItemInfoIsAliasFile) printf("alias"); |
|---|
| | 782 | else if (info.flags & kLSItemInfoIsSymlink) printf("symbolic link"); |
|---|
| | 783 | else if (info.flags & kLSItemInfoIsPlainFile) printf("document"); |
|---|
| | 784 | else printf("unknown file system entity"); |
|---|
| | 785 | |
|---|
| | 786 | if (info.flags & kLSItemInfoIsPackage) printf("package "); |
|---|
| | 787 | |
|---|
| | 788 | if (info.flags & kLSItemInfoAppPrefersNative) printf("[Carbon, prefers native OS X]"); |
|---|
| | 789 | else if (info.flags & kLSItemInfoAppPrefersClassic) printf("[Carbon, prefers Classic]"); |
|---|
| | 790 | |
|---|
| | 791 | printf("\n"); |
|---|
| | 792 | if (!(info.flags & kLSItemInfoIsContainer) || info.flags & kLSItemInfoIsPackage) { |
|---|
| | 793 | printf("\ttype: '%s'", utf8StringFromOSType(info.filetype)); |
|---|
| | 794 | printf("\tcreator: '%s'\n", utf8StringFromOSType(info.creator)); |
|---|
| | 795 | } |
|---|
| | 796 | |
|---|
| | 797 | CFStringRef bundleID = NULL; |
|---|
| | 798 | CFStringRef version = NULL; |
|---|
| | 799 | UInt32 intVersion = 0; |
|---|
| | 800 | FSRef fsr; |
|---|
| | 801 | Boolean haveFSRef = CFURLGetFSRef(url, &fsr); |
|---|
| | 802 | CFBundleRef bundle = NULL; |
|---|
| | 803 | |
|---|
| | 804 | if ((info.flags & kLSItemInfoIsPackage || info.flags & kLSItemInfoIsApplication) && |
|---|
| | 805 | ( (bundle = CFBundleCreate(NULL, url)) != NULL)) { |
|---|
| | 806 | bundleID = CFBundleGetIdentifier(bundle); |
|---|
| | 807 | if (bundleID != NULL) CFRetain(bundleID); |
|---|
| | 808 | // prefer a short version string, e.g. "1.0 Beta" instead of "51" for Safari |
|---|
| | 809 | version = CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("CFBundleShortVersionString")); |
|---|
| | 810 | if (version == NULL) |
|---|
| | 811 | version = CFBundleGetValueForInfoDictionaryKey(bundle, kCFBundleVersionKey); |
|---|
| 889 | | printf("\tversion: %s", utf8StringFromCFStringRef(version)); |
|---|
| 890 | | if (intVersion != 0) printf(" [0x%lx = %lu]", intVersion, intVersion); |
|---|
| 891 | | putchar('\n'); |
|---|
| 892 | | CFRelease(version); |
|---|
| 893 | | } |
|---|
| 894 | | |
|---|
| 895 | | // kind string |
|---|
| 896 | | err = LSCopyKindStringForURL(url, &kind); |
|---|
| 897 | | if (err != noErr) osstatusexit(err, "unable to get kind of '%s'", strBuffer); |
|---|
| 898 | | printf("\tkind: %s\n", utf8StringFromCFStringRef(kind)); |
|---|
| 899 | | CFRelease(kind); |
|---|
| 900 | | |
|---|
| 901 | | if (haveFSRef) { |
|---|
| 902 | | // content type identifier (UTI) |
|---|
| 903 | | err = LSCopyItemAttribute(&fsr, kLSRolesAll, kLSItemContentType, (CFTypeRef *)&kind); |
|---|
| 904 | | if (err == noErr) { |
|---|
| 905 | | printf("\tcontent type ID: %s\n", utf8StringFromCFStringRef(kind)); |
|---|
| 906 | | CFRelease(kind); |
|---|
| 907 | | } |
|---|
| 908 | | printMoreInfoForRef(fsr); |
|---|
| 909 | | } |
|---|
| | 813 | CFRetain(version); |
|---|
| | 814 | intVersion = CFBundleGetVersionNumber(bundle); |
|---|
| | 815 | } |
|---|
| | 816 | CFURLRef executable = CFBundleCopyExecutableURL(bundle); |
|---|
| | 817 | if (executable != NULL) { |
|---|
| | 818 | printExecutableArchitectures(executable, true); |
|---|
| | 819 | CFRelease(executable); |
|---|
| | 820 | } |
|---|
| | 821 | CFRelease(bundle); |
|---|
| | 822 | } else if (info.flags & kLSItemInfoIsPackage || !haveFSRef) { |
|---|
| | 823 | printf("\t[can't access package contents]\n"); |
|---|
| | 824 | } else if (haveFSRef) { |
|---|
| | 825 | SInt16 resFork = FSOpenResFile(&fsr, fsRdPerm); |
|---|
| | 826 | CFPropertyListRef infoPlist = NULL; |
|---|
| | 827 | if ( (err = ResError()) == noErr) { |
|---|
| | 828 | Handle h = Get1Resource('plst', 0); |
|---|
| | 829 | if (h == NULL) { |
|---|
| | 830 | err = ResError(); |
|---|
| | 831 | if (err != noErr && err != resNotFound) |
|---|
| | 832 | osstatusexit(err, "unable to read 'plst' 0 resource"); |
|---|
| | 833 | } else { |
|---|
| | 834 | CFDataRef plstData = CFDataCreate(NULL, (UInt8 *)*h, GetHandleSize(h)); |
|---|
| | 835 | CFStringRef error = NULL; |
|---|
| | 836 | infoPlist = CFPropertyListCreateFromXMLData(NULL, plstData, kCFPropertyListImmutable, &error); |
|---|
| | 837 | if (plstData != NULL) CFRelease(plstData); |
|---|
| | 838 | if (infoPlist == NULL) { |
|---|
| | 839 | printf("\t['plst' 0 resource invalid: %s]\n", utf8StringFromCFStringRef(error)); |
|---|
| | 840 | CFRelease(error); |
|---|
| | 841 | } |
|---|
| | 842 | } |
|---|
| | 843 | } |
|---|
| | 844 | if (infoPlist == NULL) { |
|---|
| | 845 | // this function should handle the 'plst' 0 case too, but it doesn't provide error messages; however, it handles the case of an unbundled Mach-O binary, so it is useful as a fallback |
|---|
| | 846 | infoPlist = CFBundleCopyInfoDictionaryForURL(url); |
|---|
| | 847 | if (infoPlist == NULL && info.flags & kLSItemInfoIsApplication && resFork == -1) |
|---|
| | 848 | printf("\t[can't open resource fork: %s]\n", osstatusstr(err)); |
|---|
| | 849 | } |
|---|
| | 850 | if (infoPlist != NULL) { |
|---|
| | 851 | // mimic CFBundle logic above |
|---|
| | 852 | bundleID = CFDictionaryGetValue(infoPlist, kCFBundleIdentifierKey); |
|---|
| | 853 | if (bundleID != NULL) CFRetain(bundleID); |
|---|
| | 854 | version = CFDictionaryGetValue(infoPlist, CFSTR("CFBundleShortVersionString")); |
|---|
| | 855 | if (version == NULL) |
|---|
| | 856 | version = CFDictionaryGetValue(infoPlist, kCFBundleVersionKey); |
|---|
| | 857 | if (version != NULL) CFRetain(version); |
|---|
| | 858 | CFRelease(infoPlist); |
|---|
| | 859 | } |
|---|
| | 860 | if (resFork != -1) { |
|---|
| | 861 | VersRecHndl vers = (VersRecHndl)Get1Resource('vers', 1); |
|---|
| | 862 | if (vers == NULL) { |
|---|
| | 863 | err = ResError(); |
|---|
| | 864 | if (err != noErr && err != resNotFound) |
|---|
| | 865 | osstatusexit(err, "unable to read 'vers' 1 resource"); |
|---|
| | 866 | } else { |
|---|
| | 867 | if (version == NULL) { // prefer 'plst' version |
|---|
| | 868 | version = CFStringCreateWithPascalString(NULL, vers[0]->shortVersion, CFStringGetSystemEncoding()); // XXX use country code instead? |
|---|
| | 869 | } |
|---|
| | 870 | intVersion = ((NumVersionVariant)vers[0]->numericVersion).whole; |
|---|
| | 871 | } |
|---|
| | 872 | CloseResFile(resFork); |
|---|
| | 873 | } |
|---|
| | 874 | printExecutableArchitectures(url, false); |
|---|
| | 875 | } |
|---|
| | 876 | |
|---|
| | 877 | if (bundleID != NULL) { |
|---|
| | 878 | printf("\tbundle ID: %s\n", utf8StringFromCFStringRef(bundleID)); |
|---|
| | 879 | CFRelease(bundleID); |
|---|
| | 880 | } |
|---|
| | 881 | if (version != NULL) { |
|---|
| | 882 | printf("\tversion: %s", utf8StringFromCFStringRef(version)); |
|---|
| | 883 | if (intVersion != 0) printf(" [0x%lx = %lu]", intVersion, intVersion); |
|---|
| | 884 | putchar('\n'); |
|---|
| | 885 | CFRelease(version); |
|---|
| | 886 | } |
|---|
| | 887 | |
|---|
| | 888 | // kind string |
|---|
| | 889 | err = LSCopyKindStringForURL(url, &kind); |
|---|
| | 890 | if (err != noErr) osstatusexit(err, "unable to get kind of '%s'", strBuffer); |
|---|
| | 891 | printf("\tkind: %s\n", utf8StringFromCFStringRef(kind)); |
|---|
| | 892 | CFRelease(kind); |
|---|
| | 893 | |
|---|
| | 894 | if (haveFSRef) { |
|---|
| | 895 | // content type identifier (UTI) |
|---|
| | 896 | err = LSCopyItemAttribute(&fsr, kLSRolesAll, kLSItemContentType, (CFTypeRef *)&kind); |
|---|
| | 897 | if (err == noErr) { |
|---|
| | 898 | printf("\tcontent type ID: %s\n", utf8StringFromCFStringRef(kind)); |
|---|
| | 899 | CFRelease(kind); |
|---|
| | 900 | } |
|---|
| | 901 | printMoreInfoForRef(fsr); |
|---|