Provide API in xpcom macutils for determining universal binary type. b=572125 r=benwa
authorJosh Aas <joshmoz@gmail.com>
Thu, 15 Jul 2010 22:32:00 -0400
changeset 47782 b141a304ad08a26961e81d29d9d7b4a20d71ce19
parent 47781 764bb4ae886c5058c5c7634d6ffb02ddfe431354
child 47784 aba8cc27fcef3ceafc61f10e0090150e1b1c0849
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersbenwa
bugs572125
milestone2.0b2pre
Provide API in xpcom macutils for determining universal binary type. b=572125 r=benwa
xpcom/base/nsIMacUtils.idl
xpcom/base/nsMacUtilsImpl.cpp
xpcom/base/nsMacUtilsImpl.h
--- a/xpcom/base/nsIMacUtils.idl
+++ b/xpcom/base/nsIMacUtils.idl
@@ -36,22 +36,29 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsISupports.idl"
 
 /**
  * nsIMacUtils: Generic globally-available Mac-specific utilities.
  */
 
-[scriptable, uuid(F6FC107C-5CBA-4C5C-A35E-B69D580D1DB6)]
+[scriptable, uuid(5E9072D7-FF95-455E-9466-8AF9841A72EC)]
 interface nsIMacUtils : nsISupports
 {
   /**
    * True when the main executable is a fat file supporting at least
    * ppc and x86 (universal binary).
    */
   readonly attribute boolean isUniversalBinary;
 
   /**
+   * Returns a string containing a list of architectures delimited
+   * by "-". Architecture sets are always in the same order:
+   * ppc > i386 > ppc64 > x86_64 > (future additions)
+   */
+  readonly attribute AString architecturesInBinary;
+
+  /**
    * True when running under binary translation (Rosetta).
    */
   readonly attribute boolean isTranslated;
 };
--- a/xpcom/base/nsMacUtilsImpl.cpp
+++ b/xpcom/base/nsMacUtilsImpl.cpp
@@ -33,103 +33,120 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsMacUtilsImpl.h"
 
 #include <CoreFoundation/CoreFoundation.h>
-#include <fcntl.h>
-#include <unistd.h>
 #include <sys/sysctl.h>
-#include <mach-o/fat.h>
 
 NS_IMPL_ISUPPORTS1(nsMacUtilsImpl, nsIMacUtils)
 
-/* readonly attribute boolean isUniversalBinary; */
-// True when the main executable is a fat file supporting at least
-// ppc and x86 (universal binary).
-NS_IMETHODIMP nsMacUtilsImpl::GetIsUniversalBinary(PRBool *aIsUniversalBinary)
+nsresult nsMacUtilsImpl::GetArchString(nsAString& archString)
 {
-  static PRBool sInitialized = PR_FALSE,
-                sIsUniversalBinary = PR_FALSE;
-
-  if (sInitialized) {
-    *aIsUniversalBinary = sIsUniversalBinary;
+  if (!mBinaryArchs.IsEmpty()) {
+    archString.Assign(mBinaryArchs);
     return NS_OK;
   }
 
-  PRBool foundPPC = PR_FALSE,
-         foundX86 = PR_FALSE;
-  CFURLRef executableURL = nsnull;
-  int fd = -1;
+  archString.Truncate();
 
-  CFBundleRef mainBundle;
-  if (!(mainBundle = ::CFBundleGetMainBundle()))
-    goto done;
-
-  if (!(executableURL = ::CFBundleCopyExecutableURL(mainBundle)))
-    goto done;
+  PRBool foundPPC = PR_FALSE,
+         foundX86 = PR_FALSE,
+         foundPPC64 = PR_FALSE,
+         foundX86_64 = PR_FALSE;
 
-  char executablePath[PATH_MAX];
-  if (!::CFURLGetFileSystemRepresentation(executableURL, PR_TRUE,
-                                          (UInt8*) executablePath,
-                                          sizeof(executablePath)))
-    goto done;
+  CFBundleRef mainBundle = ::CFBundleGetMainBundle();
+  if (!mainBundle) {
+    return NS_ERROR_FAILURE;
+  }
 
-  if ((fd = open(executablePath, O_RDONLY)) == -1)
-    goto done;
+  CFArrayRef archList = ::CFBundleCopyExecutableArchitectures(mainBundle);
+  if (!archList) {
+    return NS_ERROR_FAILURE;
+  }
 
-  struct fat_header fatHeader;
-  if (read(fd, &fatHeader, sizeof(fatHeader)) != sizeof(fatHeader))
-    goto done;
+  CFIndex archCount = ::CFArrayGetCount(archList);
+  for (CFIndex i = 0; i < archCount; i++) {
+    CFNumberRef arch = static_cast<CFNumberRef>(::CFArrayGetValueAtIndex(archList, i));
 
-  // The fat header is always stored on disk as big-endian.
-  fatHeader.magic = CFSwapInt32BigToHost(fatHeader.magic);
-  fatHeader.nfat_arch = CFSwapInt32BigToHost(fatHeader.nfat_arch);
-
-  // Main executable is thin.
-  if (fatHeader.magic != FAT_MAGIC)
-    goto done;
+    int archInt = 0;
+    if (!::CFNumberGetValue(arch, kCFNumberIntType, &archInt)) {
+      ::CFRelease(archList);
+      return NS_ERROR_FAILURE;
+    }
 
-  // Loop over each architecture in the file.  We're presently only
-  // interested in 32-bit PPC and x86.
-  for (PRUint32 i = 0 ; i < fatHeader.nfat_arch ; i++) {
-    struct fat_arch fatArch;
-    if (read(fd, &fatArch, sizeof(fatArch)) != sizeof(fatArch))
-      goto done;
+    if (archInt == kCFBundleExecutableArchitecturePPC)
+      foundPPC = PR_TRUE;
+    else if (archInt == kCFBundleExecutableArchitectureI386)
+      foundX86 = PR_TRUE;
+    else if (archInt == kCFBundleExecutableArchitecturePPC64)
+      foundPPC64 = PR_TRUE;
+    else if (archInt == kCFBundleExecutableArchitectureX86_64)
+      foundX86_64 = PR_TRUE;
+  }
 
-    // This is still part of the fat header, so byte-swap as needed.
-    fatArch.cputype = CFSwapInt32BigToHost(fatArch.cputype);
+  ::CFRelease(archList);
 
-    // Don't mask out the ABI bits.  This allows identification of ppc64
-    // as distinct from ppc.  CPU_TYPE_X86 is preferred to CPU_TYPE_I386
-    // but does not exist prior to the 10.4 headers.
-    if (fatArch.cputype == CPU_TYPE_POWERPC)
-      foundPPC = PR_TRUE;
-    else if (fatArch.cputype == CPU_TYPE_I386)
-      foundX86 = PR_TRUE;
+  // The order in the string must always be the same so
+  // don't do this in the loop.
+  if (foundPPC) {
+    mBinaryArchs.Append(NS_LITERAL_STRING("ppc"));
   }
 
-  if (foundPPC && foundX86)
-    sIsUniversalBinary = PR_TRUE;
+  if (foundX86) {
+    if (!mBinaryArchs.IsEmpty()) {
+      mBinaryArchs.Append(NS_LITERAL_STRING("-"));
+    }
+    mBinaryArchs.Append(NS_LITERAL_STRING("i386"));
+  }
+
+  if (foundPPC64) {
+    if (!mBinaryArchs.IsEmpty()) {
+      mBinaryArchs.Append(NS_LITERAL_STRING("-"));
+    }
+    mBinaryArchs.Append(NS_LITERAL_STRING("ppc64"));
+  }
 
-done:
-  if (fd != -1)
-    close(fd);
-  if (executableURL)
-    ::CFRelease(executableURL);
+  if (foundX86_64) {
+    if (!mBinaryArchs.IsEmpty()) {
+      mBinaryArchs.Append(NS_LITERAL_STRING("-"));
+    }
+    mBinaryArchs.Append(NS_LITERAL_STRING("x86_64"));
+  }
+
+  archString.Assign(mBinaryArchs);
+
+  return (archString.IsEmpty() ? NS_ERROR_FAILURE : NS_OK);
+}
 
-  *aIsUniversalBinary = sIsUniversalBinary;
-  sInitialized = PR_TRUE;
+NS_IMETHODIMP nsMacUtilsImpl::GetIsUniversalBinary(PRBool *aIsUniversalBinary)
+{
+  NS_ENSURE_ARG_POINTER(aIsUniversalBinary);
+  *aIsUniversalBinary = PR_FALSE;
+
+  nsAutoString archString;
+  nsresult rv = GetArchString(archString);
+  if (NS_FAILED(rv))
+    return rv;
+
+  // The delimiter char in the arch string is '-', so if that character
+  // is in the string we know we have multiple architectures.
+  *aIsUniversalBinary = (archString.Find("-") > -1);
 
   return NS_OK;
 }
 
+NS_IMETHODIMP nsMacUtilsImpl::GetArchitecturesInBinary(nsAString& archString)
+{
+  return GetArchString(archString);
+}
+
 /* readonly attribute boolean isTranslated; */
 // True when running under binary translation (Rosetta).
 NS_IMETHODIMP nsMacUtilsImpl::GetIsTranslated(PRBool *aIsTranslated)
 {
 #ifdef __ppc__
   static PRBool  sInitialized = PR_FALSE;
 
   // Initialize sIsNative to 1.  If the sysctl fails because it doesn't
--- a/xpcom/base/nsMacUtilsImpl.h
+++ b/xpcom/base/nsMacUtilsImpl.h
@@ -34,27 +34,34 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsMacUtilsImpl_h___
 #define nsMacUtilsImpl_h___
 
 #include "nsIMacUtils.h"
+#include "nsString.h"
 
 class nsMacUtilsImpl : public nsIMacUtils
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIMACUTILS
 
   nsMacUtilsImpl() {}
 
 private:
   ~nsMacUtilsImpl() {}
+
+  nsresult GetArchString(nsAString& archString);
+
+  // A string containing a "-" delimited list of architectures
+  // in our binary.
+  nsString mBinaryArchs;
 };
 
 // Global singleton service
 // 697BD3FD-43E5-41CE-AD5E-C339175C0818
 #define NS_MACUTILSIMPL_CLASSNAME "Mac OS X Utilities"
 #define NS_MACUTILSIMPL_CID \
  {0x697BD3FD, 0x43E5, 0x41CE, {0xAD, 0x5E, 0xC3, 0x39, 0x17, 0x5C, 0x08, 0x18}}
 #define NS_MACUTILSIMPL_CONTRACTID "@mozilla.org/xpcom/mac-utils;1"