netwerk/base/src/nsURLHelperOSX.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim:set ts=2 sw=2 et cindent: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 /* Mac OS X-specific local file uri parsing */
     8 #include "nsURLHelper.h"
     9 #include "nsEscape.h"
    10 #include "nsIFile.h"
    11 #include "nsTArray.h"
    12 #include "nsReadableUtils.h"
    13 #include <Carbon/Carbon.h>
    15 static nsTArray<nsCString> *gVolumeList = nullptr;
    17 static bool pathBeginsWithVolName(const nsACString& path, nsACString& firstPathComponent)
    18 {
    19   // Return whether the 1st path component in path (escaped) is equal to the name
    20   // of a mounted volume. Return the 1st path component (unescaped) in any case.
    21   // This needs to be done as quickly as possible, so we cache a list of volume names.
    22   // XXX Register an event handler to detect drives being mounted/unmounted?
    24   if (!gVolumeList) {
    25     gVolumeList = new nsTArray<nsCString>;
    26     if (!gVolumeList) {
    27       return false; // out of memory
    28     }
    29   }
    31   // Cache a list of volume names
    32   if (!gVolumeList->Length()) {
    33     OSErr err;
    34     ItemCount volumeIndex = 1;
    36     do {
    37       HFSUniStr255 volName;
    38       FSRef rootDirectory;
    39       err = ::FSGetVolumeInfo(0, volumeIndex, nullptr, kFSVolInfoNone, nullptr,
    40                               &volName, &rootDirectory);
    41       if (err == noErr) {
    42         NS_ConvertUTF16toUTF8 volNameStr(Substring((char16_t *)volName.unicode,
    43                                                    (char16_t *)volName.unicode + volName.length));
    44         gVolumeList->AppendElement(volNameStr);
    45         volumeIndex++;
    46       }
    47     } while (err == noErr);
    48   }
    50   // Extract the first component of the path
    51   nsACString::const_iterator start;
    52   path.BeginReading(start);
    53   start.advance(1); // path begins with '/'
    54   nsACString::const_iterator directory_end;
    55   path.EndReading(directory_end);
    56   nsACString::const_iterator component_end(start);
    57   FindCharInReadable('/', component_end, directory_end);
    59   nsAutoCString flatComponent((Substring(start, component_end)));
    60   NS_UnescapeURL(flatComponent);
    61   int32_t foundIndex = gVolumeList->IndexOf(flatComponent);
    62   firstPathComponent = flatComponent;
    63   return (foundIndex != -1);
    64 }
    66 void
    67 net_ShutdownURLHelperOSX()
    68 {
    69   delete gVolumeList;
    70   gVolumeList = nullptr;
    71 }
    73 static nsresult convertHFSPathtoPOSIX(const nsACString& hfsPath, nsACString& posixPath)
    74 {
    75   // Use CFURL to do the conversion. We don't want to do this by simply
    76   // using SwapSlashColon - we need the charset mapped from MacRoman
    77   // to UTF-8, and we need "/Volumes" (or whatever - Apple says this is subject to change)
    78   // prepended if the path is not on the boot drive.
    80   CFStringRef pathStrRef = CFStringCreateWithCString(nullptr,
    81                               PromiseFlatCString(hfsPath).get(),
    82                               kCFStringEncodingMacRoman);
    83   if (!pathStrRef)
    84     return NS_ERROR_FAILURE;
    86   nsresult rv = NS_ERROR_FAILURE;
    87   CFURLRef urlRef = CFURLCreateWithFileSystemPath(nullptr,
    88                               pathStrRef, kCFURLHFSPathStyle, true);
    89   if (urlRef) {
    90     UInt8 pathBuf[PATH_MAX];
    91     if (CFURLGetFileSystemRepresentation(urlRef, true, pathBuf, sizeof(pathBuf))) {
    92       posixPath = (char *)pathBuf;
    93       rv = NS_OK;
    94     }
    95   }
    96   CFRelease(pathStrRef);
    97   if (urlRef)
    98     CFRelease(urlRef);
    99   return rv;
   100 }
   102 static void SwapSlashColon(char *s)
   103 {
   104   while (*s) {
   105     if (*s == '/')
   106       *s = ':';
   107     else if (*s == ':')
   108       *s = '/';
   109     s++;
   110   }
   111 } 
   113 nsresult
   114 net_GetURLSpecFromActualFile(nsIFile *aFile, nsACString &result)
   115 {
   116   // NOTE: This is identical to the implementation in nsURLHelperUnix.cpp
   118   nsresult rv;
   119   nsAutoCString ePath;
   121   // construct URL spec from native file path
   122   rv = aFile->GetNativePath(ePath);
   123   if (NS_FAILED(rv))
   124     return rv;
   126   nsAutoCString escPath;
   127   NS_NAMED_LITERAL_CSTRING(prefix, "file://");
   129   // Escape the path with the directory mask
   130   if (NS_EscapeURL(ePath.get(), ePath.Length(), esc_Directory+esc_Forced, escPath))
   131     escPath.Insert(prefix, 0);
   132   else
   133     escPath.Assign(prefix + ePath);
   135   // esc_Directory does not escape the semicolons, so if a filename 
   136   // contains semicolons we need to manually escape them.
   137   // This replacement should be removed in bug #473280
   138   escPath.ReplaceSubstring(";", "%3b");
   140   result = escPath;
   141   return NS_OK;
   142 }
   144 nsresult
   145 net_GetFileFromURLSpec(const nsACString &aURL, nsIFile **result)
   146 {
   147   // NOTE: See also the implementation in nsURLHelperUnix.cpp
   148   // This matches it except for the HFS path handling.
   150   nsresult rv;
   152   nsCOMPtr<nsIFile> localFile;
   153   rv = NS_NewNativeLocalFile(EmptyCString(), true, getter_AddRefs(localFile));
   154   if (NS_FAILED(rv))
   155     return rv;
   157   nsAutoCString directory, fileBaseName, fileExtension, path;
   158   bool bHFSPath = false;
   160   rv = net_ParseFileURL(aURL, directory, fileBaseName, fileExtension);
   161   if (NS_FAILED(rv))
   162     return rv;
   164   if (!directory.IsEmpty()) {
   165     NS_EscapeURL(directory, esc_Directory|esc_AlwaysCopy, path);
   167     // The canonical form of file URLs on OSX use POSIX paths:
   168     //   file:///path-name.
   169     // But, we still encounter file URLs that use HFS paths:
   170     //   file:///volume-name/path-name
   171     // Determine that here and normalize HFS paths to POSIX.
   172     nsAutoCString possibleVolName;
   173     if (pathBeginsWithVolName(directory, possibleVolName)) {        
   174       // Though we know it begins with a volume name, it could still
   175       // be a valid POSIX path if the boot drive is named "Mac HD"
   176       // and there is a directory "Mac HD" at its root. If such a
   177       // directory doesn't exist, we'll assume this is an HFS path.
   178       FSRef testRef;
   179       possibleVolName.Insert("/", 0);
   180       if (::FSPathMakeRef((UInt8*)possibleVolName.get(), &testRef, nullptr) != noErr)
   181         bHFSPath = true;
   182     }
   184     if (bHFSPath) {
   185       // "%2F"s need to become slashes, while all other slashes need to
   186       // become colons. If we start out by changing "%2F"s to colons, we
   187       // can reply on SwapSlashColon() to do what we need
   188       path.ReplaceSubstring("%2F", ":");
   189       path.Cut(0, 1); // directory begins with '/'
   190       SwapSlashColon((char *)path.get());
   191       // At this point, path is an HFS path made using the same
   192       // algorithm as nsURLHelperMac. We'll convert to POSIX below.
   193     }
   194   }
   195   if (!fileBaseName.IsEmpty())
   196     NS_EscapeURL(fileBaseName, esc_FileBaseName|esc_AlwaysCopy, path);
   197   if (!fileExtension.IsEmpty()) {
   198     path += '.';
   199     NS_EscapeURL(fileExtension, esc_FileExtension|esc_AlwaysCopy, path);
   200   }
   202   NS_UnescapeURL(path);
   203   if (path.Length() != strlen(path.get()))
   204     return NS_ERROR_FILE_INVALID_PATH;
   206   if (bHFSPath)
   207     convertHFSPathtoPOSIX(path, path);
   209   // assuming path is encoded in the native charset
   210   rv = localFile->InitWithNativePath(path);
   211   if (NS_FAILED(rv))
   212     return rv;
   214   NS_ADDREF(*result = localFile);
   215   return NS_OK;
   216 }

mercurial