1 /* ===-- os_version_check.c - OS version checking -------------------------===
3 * The LLVM Compiler Infrastructure
5 * This file is dual licensed under the MIT and the University of Illinois Open
6 * Source Licenses. See LICENSE.TXT for details.
8 * ===----------------------------------------------------------------------===
10 * This file implements the function __isOSVersionAtLeast, used by
11 * Objective-C's @available
13 * ===----------------------------------------------------------------------===
18 #include <CoreFoundation/CoreFoundation.h>
19 #include <dispatch/dispatch.h>
20 #include <TargetConditionals.h>
27 /* These three variables hold the host's OS version. */
28 static int32_t GlobalMajor, GlobalMinor, GlobalSubminor;
29 static dispatch_once_t DispatchOnceCounter;
31 /* Find and parse the SystemVersion.plist file. */
32 static void parseSystemVersionPList(void *Unused) {
34 /* Load CoreFoundation dynamically */
35 const void *NullAllocator = dlsym(RTLD_DEFAULT, "kCFAllocatorNull");
38 const CFAllocatorRef kCFAllocatorNull =
39 *(const CFAllocatorRef *)NullAllocator;
40 typeof(CFDataCreateWithBytesNoCopy) *CFDataCreateWithBytesNoCopyFunc =
41 (typeof(CFDataCreateWithBytesNoCopy) *)dlsym(
42 RTLD_DEFAULT, "CFDataCreateWithBytesNoCopy");
43 if (!CFDataCreateWithBytesNoCopyFunc)
45 typeof(CFPropertyListCreateWithData) *CFPropertyListCreateWithDataFunc =
46 (typeof(CFPropertyListCreateWithData) *)dlsym(
47 RTLD_DEFAULT, "CFPropertyListCreateWithData");
48 /* CFPropertyListCreateWithData was introduced only in macOS 10.6+, so it
49 * will be NULL on earlier OS versions. */
50 #pragma clang diagnostic push
51 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
52 typeof(CFPropertyListCreateFromXMLData) *CFPropertyListCreateFromXMLDataFunc =
53 (typeof(CFPropertyListCreateFromXMLData) *)dlsym(
54 RTLD_DEFAULT, "CFPropertyListCreateFromXMLData");
55 #pragma clang diagnostic pop
56 /* CFPropertyListCreateFromXMLDataFunc is deprecated in macOS 10.10, so it
57 * might be NULL in future OS versions. */
58 if (!CFPropertyListCreateWithDataFunc && !CFPropertyListCreateFromXMLDataFunc)
60 typeof(CFStringCreateWithCStringNoCopy) *CFStringCreateWithCStringNoCopyFunc =
61 (typeof(CFStringCreateWithCStringNoCopy) *)dlsym(
62 RTLD_DEFAULT, "CFStringCreateWithCStringNoCopy");
63 if (!CFStringCreateWithCStringNoCopyFunc)
65 typeof(CFDictionaryGetValue) *CFDictionaryGetValueFunc =
66 (typeof(CFDictionaryGetValue) *)dlsym(RTLD_DEFAULT,
67 "CFDictionaryGetValue");
68 if (!CFDictionaryGetValueFunc)
70 typeof(CFGetTypeID) *CFGetTypeIDFunc =
71 (typeof(CFGetTypeID) *)dlsym(RTLD_DEFAULT, "CFGetTypeID");
74 typeof(CFStringGetTypeID) *CFStringGetTypeIDFunc =
75 (typeof(CFStringGetTypeID) *)dlsym(RTLD_DEFAULT, "CFStringGetTypeID");
76 if (!CFStringGetTypeIDFunc)
78 typeof(CFStringGetCString) *CFStringGetCStringFunc =
79 (typeof(CFStringGetCString) *)dlsym(RTLD_DEFAULT, "CFStringGetCString");
80 if (!CFStringGetCStringFunc)
82 typeof(CFRelease) *CFReleaseFunc =
83 (typeof(CFRelease) *)dlsym(RTLD_DEFAULT, "CFRelease");
87 char *PListPath = "/System/Library/CoreServices/SystemVersion.plist";
89 #if TARGET_OS_SIMULATOR
90 char *PListPathPrefix = getenv("IPHONE_SIMULATOR_ROOT");
93 char FullPath[strlen(PListPathPrefix) + strlen(PListPath) + 1];
94 strcpy(FullPath, PListPathPrefix);
95 strcat(FullPath, PListPath);
98 FILE *PropertyList = fopen(PListPath, "r");
102 /* Dynamically allocated stuff. */
103 CFDictionaryRef PListRef = NULL;
104 CFDataRef FileContentsRef = NULL;
105 UInt8 *PListBuf = NULL;
107 fseek(PropertyList, 0, SEEK_END);
108 long PListFileSize = ftell(PropertyList);
109 if (PListFileSize < 0)
111 rewind(PropertyList);
113 PListBuf = malloc((size_t)PListFileSize);
117 size_t NumRead = fread(PListBuf, 1, (size_t)PListFileSize, PropertyList);
118 if (NumRead != (size_t)PListFileSize)
121 /* Get the file buffer into CF's format. We pass in a null allocator here *
122 * because we free PListBuf ourselves */
123 FileContentsRef = (*CFDataCreateWithBytesNoCopyFunc)(
124 NULL, PListBuf, (CFIndex)NumRead, kCFAllocatorNull);
125 if (!FileContentsRef)
128 if (CFPropertyListCreateWithDataFunc)
129 PListRef = (*CFPropertyListCreateWithDataFunc)(
130 NULL, FileContentsRef, kCFPropertyListImmutable, NULL, NULL);
132 PListRef = (*CFPropertyListCreateFromXMLDataFunc)(
133 NULL, FileContentsRef, kCFPropertyListImmutable, NULL);
137 CFStringRef ProductVersion = (*CFStringCreateWithCStringNoCopyFunc)(
138 NULL, "ProductVersion", kCFStringEncodingASCII, kCFAllocatorNull);
141 CFTypeRef OpaqueValue = (*CFDictionaryGetValueFunc)(PListRef, ProductVersion);
142 (*CFReleaseFunc)(ProductVersion);
144 (*CFGetTypeIDFunc)(OpaqueValue) != (*CFStringGetTypeIDFunc)())
148 if (!(*CFStringGetCStringFunc)((CFStringRef)OpaqueValue, VersionStr,
149 sizeof(VersionStr), kCFStringEncodingUTF8))
151 sscanf(VersionStr, "%d.%d.%d", &GlobalMajor, &GlobalMinor, &GlobalSubminor);
155 (*CFReleaseFunc)(PListRef);
157 (*CFReleaseFunc)(FileContentsRef);
159 fclose(PropertyList);
162 int32_t __isOSVersionAtLeast(int32_t Major, int32_t Minor, int32_t Subminor) {
163 /* Populate the global version variables, if they haven't already. */
164 dispatch_once_f(&DispatchOnceCounter, NULL, parseSystemVersionPList);
166 if (Major < GlobalMajor) return 1;
167 if (Major > GlobalMajor) return 0;
168 if (Minor < GlobalMinor) return 1;
169 if (Minor > GlobalMinor) return 0;
170 return Subminor <= GlobalSubminor;
175 /* Silence an empty translation unit warning. */