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 <TargetConditionals.h>
19 #include <dispatch/dispatch.h>
26 /* These three variables hold the host's OS version. */
27 static int32_t GlobalMajor, GlobalMinor, GlobalSubminor;
28 static dispatch_once_t DispatchOnceCounter;
30 /* We can't include <CoreFoundation/CoreFoundation.h> directly from here, so
31 * just forward declare everything that we need from it. */
33 typedef const void *CFDataRef, *CFAllocatorRef, *CFPropertyListRef,
34 *CFStringRef, *CFDictionaryRef, *CFTypeRef, *CFErrorRef;
37 typedef unsigned long long CFTypeID;
38 typedef unsigned long long CFOptionFlags;
39 typedef signed long long CFIndex;
41 typedef unsigned long CFTypeID;
42 typedef unsigned long CFOptionFlags;
43 typedef signed long CFIndex;
46 typedef unsigned char UInt8;
47 typedef _Bool Boolean;
48 typedef CFIndex CFPropertyListFormat;
49 typedef uint32_t CFStringEncoding;
51 /* kCFStringEncodingASCII analog. */
52 #define CF_STRING_ENCODING_ASCII 0x0600
53 /* kCFStringEncodingUTF8 analog. */
54 #define CF_STRING_ENCODING_UTF8 0x08000100
55 #define CF_PROPERTY_LIST_IMMUTABLE 0
57 typedef CFDataRef (*CFDataCreateWithBytesNoCopyFuncTy)(CFAllocatorRef,
58 const UInt8 *, CFIndex,
60 typedef CFPropertyListRef (*CFPropertyListCreateWithDataFuncTy)(
61 CFAllocatorRef, CFDataRef, CFOptionFlags, CFPropertyListFormat *,
63 typedef CFPropertyListRef (*CFPropertyListCreateFromXMLDataFuncTy)(
64 CFAllocatorRef, CFDataRef, CFOptionFlags, CFStringRef *);
65 typedef CFStringRef (*CFStringCreateWithCStringNoCopyFuncTy)(CFAllocatorRef,
69 typedef const void *(*CFDictionaryGetValueFuncTy)(CFDictionaryRef,
71 typedef CFTypeID (*CFGetTypeIDFuncTy)(CFTypeRef);
72 typedef CFTypeID (*CFStringGetTypeIDFuncTy)(void);
73 typedef Boolean (*CFStringGetCStringFuncTy)(CFStringRef, char *, CFIndex,
75 typedef void (*CFReleaseFuncTy)(CFTypeRef);
77 /* Find and parse the SystemVersion.plist file. */
78 static void parseSystemVersionPList(void *Unused) {
80 /* Load CoreFoundation dynamically */
81 const void *NullAllocator = dlsym(RTLD_DEFAULT, "kCFAllocatorNull");
84 const CFAllocatorRef AllocatorNull = *(const CFAllocatorRef *)NullAllocator;
85 CFDataCreateWithBytesNoCopyFuncTy CFDataCreateWithBytesNoCopyFunc =
86 (CFDataCreateWithBytesNoCopyFuncTy)dlsym(RTLD_DEFAULT,
87 "CFDataCreateWithBytesNoCopy");
88 if (!CFDataCreateWithBytesNoCopyFunc)
90 CFPropertyListCreateWithDataFuncTy CFPropertyListCreateWithDataFunc =
91 (CFPropertyListCreateWithDataFuncTy)dlsym(
92 RTLD_DEFAULT, "CFPropertyListCreateWithData");
93 /* CFPropertyListCreateWithData was introduced only in macOS 10.6+, so it
94 * will be NULL on earlier OS versions. */
95 #pragma clang diagnostic push
96 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
97 CFPropertyListCreateFromXMLDataFuncTy CFPropertyListCreateFromXMLDataFunc =
98 (CFPropertyListCreateFromXMLDataFuncTy)dlsym(
99 RTLD_DEFAULT, "CFPropertyListCreateFromXMLData");
100 #pragma clang diagnostic pop
101 /* CFPropertyListCreateFromXMLDataFunc is deprecated in macOS 10.10, so it
102 * might be NULL in future OS versions. */
103 if (!CFPropertyListCreateWithDataFunc && !CFPropertyListCreateFromXMLDataFunc)
105 CFStringCreateWithCStringNoCopyFuncTy CFStringCreateWithCStringNoCopyFunc =
106 (CFStringCreateWithCStringNoCopyFuncTy)dlsym(
107 RTLD_DEFAULT, "CFStringCreateWithCStringNoCopy");
108 if (!CFStringCreateWithCStringNoCopyFunc)
110 CFDictionaryGetValueFuncTy CFDictionaryGetValueFunc =
111 (CFDictionaryGetValueFuncTy)dlsym(RTLD_DEFAULT, "CFDictionaryGetValue");
112 if (!CFDictionaryGetValueFunc)
114 CFGetTypeIDFuncTy CFGetTypeIDFunc =
115 (CFGetTypeIDFuncTy)dlsym(RTLD_DEFAULT, "CFGetTypeID");
116 if (!CFGetTypeIDFunc)
118 CFStringGetTypeIDFuncTy CFStringGetTypeIDFunc =
119 (CFStringGetTypeIDFuncTy)dlsym(RTLD_DEFAULT, "CFStringGetTypeID");
120 if (!CFStringGetTypeIDFunc)
122 CFStringGetCStringFuncTy CFStringGetCStringFunc =
123 (CFStringGetCStringFuncTy)dlsym(RTLD_DEFAULT, "CFStringGetCString");
124 if (!CFStringGetCStringFunc)
126 CFReleaseFuncTy CFReleaseFunc =
127 (CFReleaseFuncTy)dlsym(RTLD_DEFAULT, "CFRelease");
131 char *PListPath = "/System/Library/CoreServices/SystemVersion.plist";
133 #if TARGET_OS_SIMULATOR
134 char *PListPathPrefix = getenv("IPHONE_SIMULATOR_ROOT");
135 if (!PListPathPrefix)
137 char FullPath[strlen(PListPathPrefix) + strlen(PListPath) + 1];
138 strcpy(FullPath, PListPathPrefix);
139 strcat(FullPath, PListPath);
140 PListPath = FullPath;
142 FILE *PropertyList = fopen(PListPath, "r");
146 /* Dynamically allocated stuff. */
147 CFDictionaryRef PListRef = NULL;
148 CFDataRef FileContentsRef = NULL;
149 UInt8 *PListBuf = NULL;
151 fseek(PropertyList, 0, SEEK_END);
152 long PListFileSize = ftell(PropertyList);
153 if (PListFileSize < 0)
155 rewind(PropertyList);
157 PListBuf = malloc((size_t)PListFileSize);
161 size_t NumRead = fread(PListBuf, 1, (size_t)PListFileSize, PropertyList);
162 if (NumRead != (size_t)PListFileSize)
165 /* Get the file buffer into CF's format. We pass in a null allocator here *
166 * because we free PListBuf ourselves */
167 FileContentsRef = (*CFDataCreateWithBytesNoCopyFunc)(
168 NULL, PListBuf, (CFIndex)NumRead, AllocatorNull);
169 if (!FileContentsRef)
172 if (CFPropertyListCreateWithDataFunc)
173 PListRef = (*CFPropertyListCreateWithDataFunc)(
174 NULL, FileContentsRef, CF_PROPERTY_LIST_IMMUTABLE, NULL, NULL);
176 PListRef = (*CFPropertyListCreateFromXMLDataFunc)(
177 NULL, FileContentsRef, CF_PROPERTY_LIST_IMMUTABLE, NULL);
181 CFStringRef ProductVersion = (*CFStringCreateWithCStringNoCopyFunc)(
182 NULL, "ProductVersion", CF_STRING_ENCODING_ASCII, AllocatorNull);
185 CFTypeRef OpaqueValue = (*CFDictionaryGetValueFunc)(PListRef, ProductVersion);
186 (*CFReleaseFunc)(ProductVersion);
188 (*CFGetTypeIDFunc)(OpaqueValue) != (*CFStringGetTypeIDFunc)())
192 if (!(*CFStringGetCStringFunc)((CFStringRef)OpaqueValue, VersionStr,
193 sizeof(VersionStr), CF_STRING_ENCODING_UTF8))
195 sscanf(VersionStr, "%d.%d.%d", &GlobalMajor, &GlobalMinor, &GlobalSubminor);
199 (*CFReleaseFunc)(PListRef);
201 (*CFReleaseFunc)(FileContentsRef);
203 fclose(PropertyList);
206 int32_t __isOSVersionAtLeast(int32_t Major, int32_t Minor, int32_t Subminor) {
207 /* Populate the global version variables, if they haven't already. */
208 dispatch_once_f(&DispatchOnceCounter, NULL, parseSystemVersionPList);
210 if (Major < GlobalMajor)
212 if (Major > GlobalMajor)
214 if (Minor < GlobalMinor)
216 if (Minor > GlobalMinor)
218 return Subminor <= GlobalSubminor;
223 /* Silence an empty translation unit warning. */