DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (4a108e94d3e2)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef mozilla_BinaryPath_h
#define mozilla_BinaryPath_h

#include "nsXPCOMPrivate.h" // for MAXPATHLEN
#ifdef XP_WIN
#include <windows.h>
#elif defined(XP_MACOSX)
#include <CoreFoundation/CoreFoundation.h>
#elif defined(XP_UNIX)
#include <sys/stat.h>
#include <string.h>
#endif

namespace mozilla {

class BinaryPath
{
public:
#ifdef XP_WIN
  static nsresult Get(const char* argv0, char aResult[MAXPATHLEN])
  {
    wchar_t wide_path[MAXPATHLEN];
    nsresult rv = GetW(argv0, wide_path);
    if (NS_FAILED(rv)) {
      return rv;
    }
    WideCharToMultiByte(CP_UTF8, 0, wide_path, -1,
                        aResult, MAXPATHLEN, nullptr, nullptr);
    return NS_OK;
  }

private:
  static nsresult GetW(const char* argv0, wchar_t aResult[MAXPATHLEN])
  {
    if (::GetModuleFileNameW(0, aResult, MAXPATHLEN)) {
      return NS_OK;
    }
    return NS_ERROR_FAILURE;
  }

#elif defined(XP_MACOSX)
  static nsresult Get(const char* argv0, char aResult[MAXPATHLEN])
  {
    // Works even if we're not bundled.
    CFBundleRef appBundle = CFBundleGetMainBundle();
    if (!appBundle) {
      return NS_ERROR_FAILURE;
    }

    CFURLRef executableURL = CFBundleCopyExecutableURL(appBundle);
    if (!executableURL) {
      return NS_ERROR_FAILURE;
    }

    nsresult rv;
    if (CFURLGetFileSystemRepresentation(executableURL, false, (UInt8*)aResult,
                                         MAXPATHLEN)) {
      // Sanitize path in case the app was launched from Terminal via
      // './firefox' for example.
      size_t readPos = 0;
      size_t writePos = 0;
      while (aResult[readPos] != '\0') {
        if (aResult[readPos] == '.' && aResult[readPos + 1] == '/') {
          readPos += 2;
        } else {
          aResult[writePos] = aResult[readPos];
          readPos++;
          writePos++;
        }
      }
      aResult[writePos] = '\0';
      rv = NS_OK;
    } else {
      rv = NS_ERROR_FAILURE;
    }

    CFRelease(executableURL);
    return rv;
  }

#elif defined(ANDROID)
  static nsresult Get(const char* argv0, char aResult[MAXPATHLEN])
  {
    // On Android, we use the GRE_HOME variable that is set by the Java
    // bootstrap code.
    const char* greHome = getenv("GRE_HOME");
#if defined(MOZ_WIDGET_GONK)
    if (!greHome) {
      greHome = "/system/b2g";
    }
#endif

    if (!greHome) {
      return NS_ERROR_FAILURE;
    }

    snprintf(aResult, MAXPATHLEN, "%s/%s", greHome, "dummy");
    aResult[MAXPATHLEN - 1] = '\0';
    return NS_OK;
  }

#elif defined(XP_UNIX)
  static nsresult Get(const char* aArgv0, char aResult[MAXPATHLEN])
  {
    struct stat fileStat;
    // on unix, there is no official way to get the path of the current binary.
    // instead of using the MOZILLA_FIVE_HOME hack, which doesn't scale to
    // multiple applications, we will try a series of techniques:
    //
    // 1) use realpath() on argv[0], which works unless we're loaded from the
    //    PATH. Only do so if argv[0] looks like a path (contains a /).
    // 2) manually walk through the PATH and look for ourself
    // 3) give up
    if (strchr(aArgv0, '/') && realpath(aArgv0, aResult) &&
        stat(aResult, &fileStat) == 0) {
      return NS_OK;
    }

    const char* path = getenv("PATH");
    if (!path) {
      return NS_ERROR_FAILURE;
    }

    char* pathdup = strdup(path);
    if (!pathdup) {
      return NS_ERROR_OUT_OF_MEMORY;
    }

    bool found = false;
    char* token = strtok(pathdup, ":");
    while (token) {
      char tmpPath[MAXPATHLEN];
      sprintf(tmpPath, "%s/%s", token, aArgv0);
      if (realpath(tmpPath, aResult) && stat(aResult, &fileStat) == 0) {
        found = true;
        break;
      }
      token = strtok(nullptr, ":");
    }
    free(pathdup);
    if (found) {
      return NS_OK;
    }
    return NS_ERROR_FAILURE;
  }

#else
#error Oops, you need platform-specific code here
#endif

public:
  static nsresult GetFile(const char* aArgv0, nsIFile** aResult)
  {
    nsCOMPtr<nsIFile> lf;
#ifdef XP_WIN
    wchar_t exePath[MAXPATHLEN];
    nsresult rv = GetW(aArgv0, exePath);
#else
    char exePath[MAXPATHLEN];
    nsresult rv = Get(aArgv0, exePath);
#endif
    if (NS_FAILED(rv)) {
      return rv;
    }
#ifdef XP_WIN
    rv = NS_NewLocalFile(nsDependentString(exePath), true,
                         getter_AddRefs(lf));
#else
    rv = NS_NewNativeLocalFile(nsDependentCString(exePath), true,
                               getter_AddRefs(lf));
#endif
    if (NS_FAILED(rv)) {
      return rv;
    }
    NS_ADDREF(*aResult = lf);
    return NS_OK;
  }
};

}

#endif /* mozilla_BinaryPath_h */