1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/xre/MacQuirks.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,256 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 + 1.10 +#ifndef MacQuirks_h__ 1.11 +#define MacQuirks_h__ 1.12 + 1.13 +#include <sys/types.h> 1.14 +#include <sys/sysctl.h> 1.15 +#include "CoreFoundation/CoreFoundation.h" 1.16 +#include "CoreServices/CoreServices.h" 1.17 +#include "Carbon/Carbon.h" 1.18 + 1.19 +// This file is a copy and paste from existing methods from 1.20 +// libxul. This is intentional because this interpose 1.21 +// library does not link with libxul. 1.22 + 1.23 +struct VersionPart { 1.24 + int32_t numA; 1.25 + 1.26 + const char *strB; // NOT null-terminated, can be a null pointer 1.27 + uint32_t strBlen; 1.28 + 1.29 + int32_t numC; 1.30 + 1.31 + char *extraD; // null-terminated 1.32 +}; 1.33 + 1.34 +/** 1.35 + * Parse a version part into a number and "extra text". 1.36 + * 1.37 + * @returns A pointer to the next versionpart, or null if none. 1.38 + */ 1.39 +static char* 1.40 +ParseVP(char *part, VersionPart &result) 1.41 +{ 1.42 + char *dot; 1.43 + 1.44 + result.numA = 0; 1.45 + result.strB = nullptr; 1.46 + result.strBlen = 0; 1.47 + result.numC = 0; 1.48 + result.extraD = nullptr; 1.49 + 1.50 + if (!part) 1.51 + return part; 1.52 + 1.53 + dot = strchr(part, '.'); 1.54 + if (dot) 1.55 + *dot = '\0'; 1.56 + 1.57 + if (part[0] == '*' && part[1] == '\0') { 1.58 + result.numA = INT32_MAX; 1.59 + result.strB = ""; 1.60 + } 1.61 + else { 1.62 + result.numA = strtol(part, const_cast<char**>(&result.strB), 10); 1.63 + } 1.64 + 1.65 + if (!*result.strB) { 1.66 + result.strB = nullptr; 1.67 + result.strBlen = 0; 1.68 + } 1.69 + else { 1.70 + if (result.strB[0] == '+') { 1.71 + static const char kPre[] = "pre"; 1.72 + 1.73 + ++result.numA; 1.74 + result.strB = kPre; 1.75 + result.strBlen = sizeof(kPre) - 1; 1.76 + } 1.77 + else { 1.78 + const char *numstart = strpbrk(result.strB, "0123456789+-"); 1.79 + if (!numstart) { 1.80 + result.strBlen = strlen(result.strB); 1.81 + } 1.82 + else { 1.83 + result.strBlen = numstart - result.strB; 1.84 + 1.85 + result.numC = strtol(numstart, &result.extraD, 10); 1.86 + if (!*result.extraD) 1.87 + result.extraD = nullptr; 1.88 + } 1.89 + } 1.90 + } 1.91 + 1.92 + if (dot) { 1.93 + ++dot; 1.94 + 1.95 + if (!*dot) 1.96 + dot = nullptr; 1.97 + } 1.98 + 1.99 + return dot; 1.100 +} 1.101 + 1.102 + 1.103 +// compare two null-terminated strings, which may be null pointers 1.104 +static int32_t 1.105 +ns_strcmp(const char *str1, const char *str2) 1.106 +{ 1.107 + // any string is *before* no string 1.108 + if (!str1) 1.109 + return str2 != 0; 1.110 + 1.111 + if (!str2) 1.112 + return -1; 1.113 + 1.114 + return strcmp(str1, str2); 1.115 +} 1.116 + 1.117 +// compare two length-specified string, which may be null pointers 1.118 +static int32_t 1.119 +ns_strnncmp(const char *str1, uint32_t len1, const char *str2, uint32_t len2) 1.120 +{ 1.121 + // any string is *before* no string 1.122 + if (!str1) 1.123 + return str2 != 0; 1.124 + 1.125 + if (!str2) 1.126 + return -1; 1.127 + 1.128 + for (; len1 && len2; --len1, --len2, ++str1, ++str2) { 1.129 + if (*str1 < *str2) 1.130 + return -1; 1.131 + 1.132 + if (*str1 > *str2) 1.133 + return 1; 1.134 + } 1.135 + 1.136 + if (len1 == 0) 1.137 + return len2 == 0 ? 0 : -1; 1.138 + 1.139 + return 1; 1.140 +} 1.141 + 1.142 +// compare two int32_t 1.143 +static int32_t 1.144 +ns_cmp(int32_t n1, int32_t n2) 1.145 +{ 1.146 + if (n1 < n2) 1.147 + return -1; 1.148 + 1.149 + return n1 != n2; 1.150 +} 1.151 + 1.152 +/** 1.153 + * Compares two VersionParts 1.154 + */ 1.155 +static int32_t 1.156 +CompareVP(VersionPart &v1, VersionPart &v2) 1.157 +{ 1.158 + int32_t r = ns_cmp(v1.numA, v2.numA); 1.159 + if (r) 1.160 + return r; 1.161 + 1.162 + r = ns_strnncmp(v1.strB, v1.strBlen, v2.strB, v2.strBlen); 1.163 + if (r) 1.164 + return r; 1.165 + 1.166 + r = ns_cmp(v1.numC, v2.numC); 1.167 + if (r) 1.168 + return r; 1.169 + 1.170 + return ns_strcmp(v1.extraD, v2.extraD); 1.171 +} 1.172 + 1.173 +/* this is intentionally not static so that we don't end up making copies 1.174 + * anywhere */ 1.175 +int32_t 1.176 +NS_CompareVersions(const char *A, const char *B) 1.177 +{ 1.178 + char *A2 = strdup(A); 1.179 + if (!A2) 1.180 + return 1; 1.181 + 1.182 + char *B2 = strdup(B); 1.183 + if (!B2) { 1.184 + free(A2); 1.185 + return 1; 1.186 + } 1.187 + 1.188 + int32_t result; 1.189 + char *a = A2, *b = B2; 1.190 + 1.191 + do { 1.192 + VersionPart va, vb; 1.193 + 1.194 + a = ParseVP(a, va); 1.195 + b = ParseVP(b, vb); 1.196 + 1.197 + result = CompareVP(va, vb); 1.198 + if (result) 1.199 + break; 1.200 + 1.201 + } while (a || b); 1.202 + 1.203 + free(A2); 1.204 + free(B2); 1.205 + 1.206 + return result; 1.207 +} 1.208 + 1.209 + 1.210 +static void 1.211 +TriggerQuirks() 1.212 +{ 1.213 + int mib[2]; 1.214 + 1.215 + mib[0] = CTL_KERN; 1.216 + mib[1] = KERN_OSRELEASE; 1.217 + // we won't support versions greater than 10.7.99 1.218 + char release[sizeof("10.7.99")]; 1.219 + size_t len = sizeof(release); 1.220 + // sysctl will return ENOMEM if the release string is longer than sizeof(release) 1.221 + int ret = sysctl(mib, 2, release, &len, nullptr, 0); 1.222 + // we only want to trigger this on OS X 10.6, on versions 10.6.8 or newer 1.223 + // Darwin version 10 corresponds to OS X version 10.6, version 11 is 10.7 1.224 + // http://en.wikipedia.org/wiki/Darwin_(operating_system)#Release_history 1.225 + if (ret == 0 && NS_CompareVersions(release, "10.8.0") >= 0 && NS_CompareVersions(release, "11") < 0) { 1.226 + CFBundleRef mainBundle = CFBundleGetMainBundle(); 1.227 + if (mainBundle) { 1.228 + CFRetain(mainBundle); 1.229 + 1.230 + CFStringRef bundleID = CFBundleGetIdentifier(mainBundle); 1.231 + if (bundleID) { 1.232 + CFRetain(bundleID); 1.233 + 1.234 + CFMutableDictionaryRef dict = (CFMutableDictionaryRef)CFBundleGetInfoDictionary(mainBundle); 1.235 + CFDictionarySetValue(dict, CFSTR("CFBundleIdentifier"), CFSTR("org.mozilla.firefox")); 1.236 + 1.237 + // Trigger a load of the quirks table for org.mozilla.firefox. 1.238 + // We use different function on 32/64bit because of how the APIs 1.239 + // behave to force a call to GetBugsForOurBundleIDFromCoreservicesd. 1.240 +#ifdef __i386__ 1.241 + ProcessSerialNumber psn; 1.242 + ::GetCurrentProcess(&psn); 1.243 +#else 1.244 + SInt32 major; 1.245 + ::Gestalt(gestaltSystemVersionMajor, &major); 1.246 +#endif 1.247 + 1.248 + // restore the original id 1.249 + dict = (CFMutableDictionaryRef)CFBundleGetInfoDictionary(mainBundle); 1.250 + CFDictionarySetValue(dict, CFSTR("CFBundleIdentifier"), bundleID); 1.251 + 1.252 + CFRelease(bundleID); 1.253 + } 1.254 + CFRelease(mainBundle); 1.255 + } 1.256 + } 1.257 +} 1.258 + 1.259 +#endif //MacQuirks_h__