Mavericks のタグをちょっと調べた

カラータグを複数つけると見た目は複数適用されているが、ラベル属性は1種類しか適用されない。kMDItemFSLabel は複数の値を持てない。ラベルで検索するとラベル属性として採用されているひとつの値でしかヒットしない。

Finder でのタグ編集時「,」は区切り文字として扱われる。「,」を含む文字列をペーストしても分割される。

Automator などでラベルを付けるとデフォルトのカラータグが付く。デフォルトのタグ名を変更、あるいは削除している場合も、システムデフォルトの「レッド」「ブルー」などが付く。例えば青いラベルを「Blue」に変えていたとしても付加されるタグは「ブルー」となり、「Blue」タグでは検索にかからない。ラベルは青いものがちゃんと付いていて、ラベルで検索すると該当する。
カラータグを削除している場合は「ブルー」のタグが付き、ラベルも青くなるが、タグ自体には色が付かない。タグとは関係なくカラーラベル属性を持っているように見える。タグを編集すると「ブルー」タグに色が付く。タグに色が付く前に削除するとファイルのラベル属性も消える。関連してないわけではないらしい。

kMDItemUserTags と com.apple.metadata:_kMDItemUserTags は厳密には違う。前者はタグの名前しか持たないが、後者はカラーラベル情報も持っている。 参考:OS X 10.9 Mavericks: The Ars Technica Review | Ars Technica

Finder 環境設定の挙動

  • タグを既にリストに存在する名前にリネーム→既に使用されていると言われ変更できない
  • タグを削除→ファイルに付いているタグも消える。 デフォルトのカラータグを削除すると旧 OS で付けていたカラーラベル属性も飛んでしまうので注意

zip で退避させるとどうなるか

  • 無色のタグを付けたファイルを zip にして退避→タグを削除→zip 解凍→ファイルにタグは残っている
  • →そのタグに色を付ける→zip 解凍→解凍したファイルに色は付かない(kMDItemFSLabel=0)
  • →更に色を変える→ここで解凍したファイルに色がつく
  • 解凍後 Finder 環境設定でタグ名を変更→解凍したファイルのタグも変わる。色は付かないまま
  • →しかし情報を見るなどで表示すると色付きタグになっている→他のタグを追加してみると更新されて色が付く

カラータグを付けたファイルを zip にして退避

  • →そのタグの色を変える。→zip 解凍→タグ名はそのまま色が変わる(現在のタグに付いている色になる)
  • →そのタグの色を戻す→zip 解凍→タグ名はそのまま色もそのまま(現在のタグに付いている色==圧縮前の色)
  • →そのタグを無色に→zip 解凍→タグ名はそのまま無色(現在のタグ同様無色になる)
  • →そのタグを削除→zip 解凍→ファイルにタグは残っている色も付いている(圧縮前の色)
  • 解凍した直後なぜか一瞬デフォルトのカラータグ名が見える

無色タグとカラータグを付けて zip 退避

  • →無色タグに色を付ける→zip 解凍→無色タグだったタグに色が付く(無色タグのみと挙動が異なる)
  • →カラータグを無色に→zip 解凍→両方無色(現在のタグ同様無色になる)
  • →カラータグを削除→zip 解凍→両方無色だが圧縮前の色が残っている変な状態

以上、条件がややこしくて間違ってるとこがあるかもしれません。圧縮解凍のケースはそんなに重要じゃないです、文章量を稼いでるだけです。とりあえずデフォルトカラータグの削除には気をつけましょう。

Mavericks で U.S.を入力ソースから削除する

Mavericks にしたら入力ソースから U.S. を削除する方法が分かり辛いというお話。ことえり を使っている場合は普通に削除できると思う。かわせみ など他社製のものを使っている場合このケースに該当することがあるかもしれない。

注意:使用している かわせみ は Mavericks 正式対応前のバージョン 1.1.5 です。

OS のアップデートを済ませるとこうなっていた。

f:id:hetima:20131026031004p:plain

U.S. は不要なのでキーボード環境設定を開いて消そうとした。しかし U.S. を選択すると削除ボタンが使用不可になってしまう。

f:id:hetima:20131026031039p:plain

どうやら英語の入力ソースは必ず1個登録していないといけないようだ。そのためか英語の入力ソースが2個だけ登録されている場合片方が削除できなくなる。どちらが削除不可能になるかと言うとリストの並びで上の方。じゃあ残したいものを上に、いらないものを下になるように選べばいいではないか、ということになる。しかし かわせみ の英字よりも下に配置される英語入力ソースが存在しないのだ。
「手持ちのの英語入力ソースのうち最後尾ものを単独で英語入力ソースとして指定することはできない」ということだ。これは限りなくバグに近い仕様だ。

この仕様がちょっと意味が分からなくて片方消して残り1個だけになった時点で削除不可能にすればいいし、複数選択して削除するときは他に残ってないかチェックすればいいのに。

解決方法

日本語ソースから ことえり を追加する。ことえり は各種入力モードを内包しているので英語入力モードも追加した扱いになる。右側のビューで個別にオンオフできる。これで英語を扱えるソースが3個になったので好きなものを削除できる。U.S. を消してしまおう。

f:id:hetima:20131026031116p:plain

そうすると英語ソースは残り2個になり、上記ルールに従っているのかは不明だが、結果的には上に配置されている ことえり の英語入力のチェックを外せなくなる。それでは消せないソースが ことえり に変わっただけだが、なぜか左リストの ことえり 自体は削除できるので かわせみ のひらがなと英字だけを残すことができた。

ちなみにここで ことえり を残して英語入力を ことえり だけにすると ことえり は削除できなくなる。
UI が変わって手順の再現がちょっと面倒になっただけで、仕様そのものは 10.8 以前と変わってない気がする。

エクスポートされていない関数のアドレスを調べる (OS X用)

(function とか symbol とかの使い分けがよく分からないので、文中は「関数」で統一しています)

HTSymbolHook というライブラリを github で公開しました。mach_overrideObjective-C ラッパーで、関数ポインタをオーバーライドできるライブラリです。単なるラッパーではなく関数ポインタを探す機能を付けました。

mach_override は関数ポインタを関数ポインタで置き換える機能を持っています。以前は置き換える対象を関数名のC文字列で指定することができていたのですが現行バージョンではなくなっています。つまり関数ポインタを自前で探す必要があります。OS X はバージョンを重ねるごとに関数ポインタを探すことが難しくなり、現状 dlsym() という関数を使うくらいしか簡単な方法はありません。しかし dlsym() はエクスポートされている関数しか探せないという行儀の良い仕様なのです。オーバーライドしたい関数がエクスポートされているとは限りません。

いろいろ調べ回った結果、Mach-O イメージを直接走査すればエクスポートされていない関数も取得できることが分かりました。大雑把に書くと

  • mach_header_64 構造体を取得
  • それを起点に LC_SYMTAB load command から symtab_command 構造体を取得
  • __LINKEDIT セグメントからオフセット情報を取得
  • symtab_command 構造体にある関数情報のオフセットを __LINKEDIT の情報で補正
  • nlist_64 構造体のリストと関数名の文字列リストが手に入る

という手順でした。symtab_command の構造は Mach-Oのシンボルテーブルを読み込む - teru_kusuの日記 にて分かりやすい図解がしてあり参考になりました。

実行コードとしてロードされている Mach-O イメージの場合これだけではまだ不十分で、 _dyld_get_image_vmaddr_slide() という関数を使ってMach-O イメージ全体にかかっているオフセットを補正する必要もありました。あとは nlist_64 構造体のリストを検索して関数名が一致すればめでたく発見です。エクスポートされていない関数も取れます。

というような機能を HTSymbolHook に内蔵しています。

で、これの実行速度はどうなのかというと、dlsym() と比較すると遅いです。300倍くらい遅いです! どうやらエクスポートされている関数は読み込んだ後にソートされて二分探索できるようになっているみたいなのです。速度を気にするような場面じゃないのでこのままでもいいのですが、高速化する手段も用意しました。nlist_64 の順番は固定なので、あらかじめ目的の関数が何番目にあるのか調べておき、そのインデックスから検索開始できるようにもしています(実際にはバージョンアップ対策で何個か前から検索した方が良いと思います)。これは一発で見つかるので dlsym() より速いです。

詳細はソース見てね、ということで https://github.com/hetima/HTSymbolHook