macOSからWindowsへのパス変換でハマった所とその解決法

[グレンジ Advent Calendar 2018](https://qiita.com/advent-calendar/2018/grenge) 6日目担当の soyo と申します。
グレンジでcocos2d-xによるゲーム開発のクライアントエンジニアをしております。

とはいえ、今回の記事はcocos2d-xとはまったく関係ありません。
簡単そうなパス変換ですが、意外と躓いてしまったので、その解決方法をまとめたいと思います。
(日本語が拙いところがありますが、ご容赦ください)

# 技術・環境
+ macOS
+ Automator
+ AppleScript
+ JavaScript

# やりたいと思ったきっかけ
__最初は、macOSのパスをWindowsのパスに変換して共有したいだけでした__が、
その時に、一つ問題が発生しました。

どういう問題かというと、
いつもの手順は、まず共有サーバーに置いてあるファイルの詳細情報からパスをコピーします。
<img width="316" alt="2.png" src="https://qiita-image-store.s3.amazonaws.com/0/320392/6bea5f13-9172-e85f-9fd5-18814ba8534f.png">
そして、ネットのパス変換ツールで変換して、
チャットワークで共有すれば、これで大丈夫かなと思いました。
![4.png](https://qiita-image-store.s3.amazonaws.com/0/320392/89fdb682-3522-4ed5-8613-7a2392d6ccc1.png)
 __が、アクセスできないだと？！__
![4.5.png](https://qiita-image-store.s3.amazonaws.com/0/320392/f56b325b-31d7-c632-db33-9830de042615.png)
これは困るので、この際は自作してみようと思います！

# 発生した問題
## 濁点問題
送ったリンクをテキストエディターに貼ると、なぜか濁点がずれているようです。
<img width="516" alt="5.png" src="https://qiita-image-store.s3.amazonaws.com/0/320392/1bdd23e1-a5d3-4216-198f-c481c8db2ab4.png">
ネットで調べると、[__Macでファイル名をコピペすると濁点と半濁点がおかしくなる__](https://qiita.com/damassima/items/1813af7e501994aa0cf8)という記事がありました。
この記事によると、macOSの自動化ツールAutomatorでシェルを実行すれば解決できそうですね！

## マウント先のパス問題
結果、Automatorでシェル実行してコピーされたパスは以下のものとなりました…
<img width="418" alt="volumes.png" src="https://qiita-image-store.s3.amazonaws.com/0/320392/9d2d0f6c-c850-e18a-d19a-9ff039165def.png">
これで、マウント先のパスが簡単に取れないことがわかりました。
でも、一応エンジニアである私が__こんなところでやられてたまるか！__

マウント先のパスを見る方法なら知っていますよ！

```bash
$ mount | grep "[デバイス名]"
```
これでマウント先のパスを見れます！
<img width="550" alt="7.png" src="https://qiita-image-store.s3.amazonaws.com/0/320392/407a9a78-8dd9-89c3-a1c6-851a69f14301.png">
そして、AutomatorはAppleScriptというスクリプト言語が使えますので、
ネットで見つけた[パスを変換するコード](https://apple.stackexchange.com/questions/307089/convert-a-pc-path-to-mac-path-with-applescript)で、一応動きました！

と思ったら、なんと次の問題が発生してしまいました…
<img width="420" alt="14.png" src="https://qiita-image-store.s3.amazonaws.com/0/320392/ac57c845-c59e-2901-95a8-d6fd1b79fca7.png">

## UTF-8問題
上記のエラーについて調べた結果、
__マウント先のパスがUTF-8文字が存在する場合のみ__エラーが出ます。

例：
<img width="426" alt="12.png" src="https://qiita-image-store.s3.amazonaws.com/0/320392/4627699d-c62b-fc35-1f63-4fa818de9f2c.png">
この場合は

``` bash
$ mount | grep "[デバイス名]"
```

を実行すると
<img width="555" alt="8.png" src="https://qiita-image-store.s3.amazonaws.com/0/320392/45a04b7c-9378-82fb-589f-cad558ea0381.png">
なんと[__パーセントエンコーディング__](https://ja.wikipedia.org/wiki/%E3%83%91%E3%83%BC%E3%82%BB%E3%83%B3%E3%83%88%E3%82%A8%E3%83%B3%E3%82%B3%E3%83%BC%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0)？！
しかも後ろの部分(onから)は漢字のままになっています！

そのまま化けた文字が使えると思うのか！
<img width="552" alt="10.png" src="https://qiita-image-store.s3.amazonaws.com/0/320392/e241b4e0-0935-75fa-1784-323b66b0cf6a.png">
......
<img width="392" alt="11.png" src="https://qiita-image-store.s3.amazonaws.com/0/320392/80359add-aa7a-4e3d-1414-80a652038e6a.png">
使えますね。

わかったわかった、自分もこういう風に対応すれば良いでしょう。

実はAutomatorではJavaScriptも使えそうです。
<img width="242" alt="script.png" src="https://qiita-image-store.s3.amazonaws.com/0/320392/df414609-d18f-2a95-b639-98a61212b44f.png">
JavaScriptでは[__decodeURI__](https://msdn.microsoft.com/ja-jp/library/ht8a077w(v=vs.94).aspx)という関数が存在して、デコードができそうです。
さらに、[__normalize('NFC')__](https://msdn.microsoft.com/ja-jp/library/mt146836(v=vs.94).aspx)という関数で濁点の問題も解決できそうです。

```javascript
function run(input, parameters) {
	return decodeURI(input).normalize('NFC');
}
```

これで、やっと正しい変換ができるようになりました。
<img width="479" alt="13.png" src="https://qiita-image-store.s3.amazonaws.com/0/320392/020ef2c0-8444-bda1-cfc9-5fd5b029b193.png">
ファイルの右クリックメニューからワンクリックでWindowsのパスをコピーすることができます。
<img width="410" alt="15.png" src="https://qiita-image-store.s3.amazonaws.com/0/320392/19b661ef-5ba0-cba8-0bc3-5054b57c4901.png">

もちろん、複数ファイルのパスも変換できます。
<img width="585" alt="16.png" src="https://qiita-image-store.s3.amazonaws.com/0/320392/9f2f8dd4-3e1e-ca99-6284-d9d41b0bfaa2.png">
<img width="519" alt="17.png" src="https://qiita-image-store.s3.amazonaws.com/0/320392/3996e60b-cfd5-bef3-967c-e8494341e2e5.png">


# 最終的に実装できたもの
## Automator設定
<img width="481" alt="auto.png" src="https://qiita-image-store.s3.amazonaws.com/0/320392/30d54606-79fa-e887-8652-a1d696114e63.png">
<img width="664" alt="setting.png" src="https://qiita-image-store.s3.amazonaws.com/0/320392/7bdf6e06-c376-4fe4-b2b0-771bb372ff49.png">


## AppleScriptコード(smbのみ対応、afpはまだ)
```applescript
on splitString(str, delimiter)
	set OldDelims to AppleScript's text item delimiters
	set AppleScript's text item delimiters to delimiter
	set stringList to every text item of str
	set AppleScript's text item delimiters to OldDelims
	return stringList
end splitString

on getRealPath(input_file_path)
	set smbPrefix to "/Volumes/"
	if input_file_path starts with smbPrefix then
		set file_path to text items 2 thru -1 of splitString(input_file_path, smbPrefix) as string
		set mount_name to text item 1 of splitString(file_path, "/") as string
		set shell_command to "mount | grep \" on " & smbPrefix & mount_name & "\""
		set mount_path to do shell script shell_command
		set mount_path to text items 2 thru -1 of splitString(mount_path, "@") as string
		set mount_path to text item 1 of splitString(mount_path, " on /Volumes") as string
		set file_path to text items 2 thru -1 of splitString(file_path, mount_name & "/") as string
		return "smb://" & mount_path & "/" & file_path
	end if
	return input_file_path
end getRealPath

on searchReplace(theText, SearchString, ReplaceString)
	set OldDelims to AppleScript's text item delimiters
	set AppleScript's text item delimiters to SearchString
	set newText to text items of theText
	set AppleScript's text item delimiters to ReplaceString
	set newText to newText as text
	set AppleScript's text item delimiters to OldDelims
	return newText
end searchReplace

on toWindowsPath(file_path)
	set win_path to file_path
	set win_path to searchReplace(win_path, "<", "")
	set win_path to searchReplace(win_path, ">.", "")
	set win_path to searchReplace(win_path, ">", "")
	set win_path to searchReplace(win_path, "smb://", "\\\\")
	set win_path to searchReplace(win_path, "/", "\\")
	return win_path
end toWindowsPath

on run {input, parameters}
	set results to ""
	repeat with input_file in input
		set real_path to getRealPath(the POSIX path of input_file)
		if real_path starts with "smb://" then
			set results to results & toWindowsPath(real_path) & return
		else
			display dialog "ローカルパスをWindows用パスに変換できません" buttons {"OK"} default button "OK"
			return ""
		end if
	end repeat
	return results
end run
```

# まとめ
Finderの詳細情報から見せるmacOS詳細パスはこんなに複雑だとは思いませんでした。

ただ、濁点・マウント先のパス取得・UTF-8問題といういろんな山をこえた結果、
ワンクリックでパス変換できるようなものができて嬉しかったです。

ちなみに、社内で何人かに使ってもらった結果、結構好評でした。