iPhone Tips/AddressBookの解析/FW 3.1.2/テーブル構造

出典: Fukudat.com

基本構造はFW 2.0.2時点と変わっていない. 以下のテーブルが存在する.

テーブル名 説明
ABGroup 不明.多分,連絡先のグループなのだろうが,iPhoneの連絡先アプリにはそのような機能がない.
ABGroupChanges 不明.同上.
ABGroupMembers 不明.同上.
ABMultiValue 連絡先に複数の値をとることができる属性値
ABMultiValueEntry 上記のサブ属性値(住所で用いる)
ABMultiValueEntryKey サブ属性のラベル.すなわち,Street, State, ZIP, City, CountryCodeが入る.その他の値は入らないと思われるが,初期状態はなぜか空.
ABMultiValueLabel 属性のラベル.自宅, 勤務先, 携帯,iPhoneなど.
ABPerson この1行が1連絡先となる.メインのテーブル.
ABPersonChanges 変更された連絡先を記録する.多分syncのため.
ABPersonMultiValueDeletes 削除された属性値を記録するために使われるのだと思われる.
ABPersonSearchKey 連絡先アプリで使われる検索インデックス.
ABPhoneLastFour 電話番号下4桁と連絡先エントリの対応付け.メールアプリや通話履歴が連絡先を参照するのに使用される.
ABRecent 不明.
ABStore 不明.
FirstSortSectionCount 不明.見出しごとに含まれるエントリの数を数えている?
LastSortSectionCount 不明.同上.
_SqliteDatabaseProperties バージョン番号など

1 ABMultiValue

FW 2.0.2から変更なし.

ABMultiValue table
カラム名 データ型 コメント
UID integer unique identifier (primary key)
record_id integer ABPerson の rowid
property integer 属性種別 (下の表を参照)
identifier integer 同じrecord_id, 同じpropertyをもつ属性値の中で0から番号が振られる.
label integer ABMultiValueLabelの行番号
value text

propertyの値はDB中には定義されていない.iPhoneの連絡先アプリで試したところ,以下の値が出現した. ここにない値が何を意味するのかは不明.

属性種別
property 説明
3 電話番号
4 メールアドレス
5 住所 (値は ABMultiValueEntryに格納される)
12 日付 (値は iPhone時間)
13 メモ?
16 着信音 ('itunes:' + 16進数16桁 (64bit))
22 URL

2 ABMultiValueEntry

FW 2.0.2から変更なし.

ABMultiValueEntry table
カラム名 データ型 コメント
parent_id integer ABMultiValue (親属性)テーブルのUIDを参照している
key integer サブ属性種別 ABMultiValueEntryKeyを参照している
value text サブ属性の値

サブ属性の値と,サブ属性が所属する親属性の関係を格納するテーブル.

サブ属性を持つ属性はすなわち住所で,サブ属性とは国コード,郵便番号,都道府県,市区町村,町名番地のこと.

サブ属性の種類はABMultiValueEntryKeyに格納される.

3 ABMultiValueEntryKey

ABMultiValueEntryKey table
カラム名 データ型 コメント
value text ABMultiValueEntryのkeyがあらわす属性の種類

サブ属性の種別を保持するテーブル.

格納される値は決まっているのだが,DBが初期化された状態では空で,最初の住所データが入力された時点で値が入る.アプリの中に埋め込む定数でもよいような気がするが,なぜか可変である.

4 ABMultiValueLabel

ABMultiValueLabel table
カラム名 データ型 コメント
value text ABMultiValueのpropertyがあらわす属性のラベル

(親)属性のラベルを保持するテーブル.

ABMultiValueEntryKeyと違って格納される値は決まっていないが,最初のデータが入力された時点で次の値が入力される: iPhone, _$!<Home>!$_, _$!<Work>!$_, _$!<Pager>!$_, _$!<HomePage>!$_, _$!<Anniversary>!$_.この_$!<XXX>!$_はアプリが自宅,勤務先...などに置き換えてくれる模様.

カスタムラベルを定義すると,そのラベルがこのテーブルに格納される.

5 ABPerson

ABPerson table
カラム名 データ型 コメント
ROWID INTEGER 行番号 primary key.
First text ファーストネーム
Last text ラストネーム
Middle text ミドルネーム
FirstPhonetic text ファーストネーム読み
MiddlePhonetic text ミドルネーム読み
LastPhonetic text ラストネーム読み
Organization text 会社
Department text 部署
Note text メモ
Kind text 不明 (種類?)
Birthday text 誕生日
JobTitle text 役職
NickName text ニックネーム
Prefix text プレフィックス
Suffix text サフィックス
FirstSort text ファーストネームでのソートするためのキー
LastSort text ファーストネームでソートするためのキー
CreationDate integer 作成日
ModificationDate integer 更新日
CompositeNameFallback text 不明
ExternalIdentifier text 不明
StoreID integer 不明
DisplayName text 不明
ExternalRepresentation text 不明
FirstSortSection text ファーストネームでソートする場合の見出しキー
LastSortSection text ファーストネームでソートする場合の見出しキー
FirstSortLanguageIndex integer ファーストネームでソートする場合の見出しの文字種
LastSortLanguageIndex integer ファーストネームでソートする場合の見出しの文字種

連絡先を格納するメインのテーブルである.

不明とあるカラムはiPhoneの連絡先アプリでは使用されないので,どのような意味があるのか判らない.

それ以外のカラムの大半は,概ね名前から判る自明な役割を持っているが,{First|Last}Sortは({First|Last}Phoneticに格納されている)名・姓の読みを特殊なエンコーディングによって変換した値が入る. このエンコード方法を解析するのには苦労した.以下に詳説する.

5.1 SortKeyのエンコーディング

FirstSort,LastSortは名前の読みを,以下の規則でエンコードしたバイナリを格納する.

  • FirstSortは(1)FirstPhonetic,(2)LastPhonetic,(3)First, (4)Last, (5)Organizationの順でエンコードしたものを,0x02で区切ってつなげた値を保持する.未定義のフィールドはスキップする
  • LastSortは(1)LastPhonetic,(2)FirstPhonetic,(3)Last, (4)First, (5)Organizationの順でエンコードしたものを,0x02で区切ってつなげた値を保持する.

それぞれのフィールドは以下の規則に従って1文字ずつエンコードされる.

  • 空白文字の場合,(0x02)の1バイトに変換(0x02はフィールドのセパレータらしい).
  • 数字の場合,(0x29), (0x7c+数値) の2バイトに変換.
  • アルファベットの場合,大文字に変換した上で「ABC...XYZ」26文字中の順位をN (N=0..25) として,(0x2c+2N)の1バイトに変換.
  • ひらがな・カタカナの場合,濁音・半濁音を取り除き,小文字(ぁぃぅぇぉっゃゅょ)は大文字に変換した後,「あいうえおかきくけこ...らりるれろわゐゑをん」50音中の順位をN (N=0..) として,(0xc2), (0xa3), (0x20+2N) の3バイトに変換.
  • 漢字は...試してないので不明.

ABPersonSearchKeyもこれと酷似した(しかし微妙に異なる)エンコーディングを用いている.

6 ABPersonChanges

ABPersonChanges table
カラム名 データ型 コメント
record INTEGER 不明
type INTEGER 不明
Image INTEGER 不明
ExternalIdentifier TEXT 不明
StoreID INTEGER 不明

未調査

7 ABPersonMultiValueDeletes

ABPersonMultiValueDeletes table
カラム名 データ型 コメント
record_id INTEGER ABMultiValue.rowid
property_id INTEGER ABMultiValue.property
identifier INTEGER ABMultiValue.identifier

未調査.多分,ABMultiValue から削除されたレコードを記録しているものと思われる.sync のためか.

8 ABPersonSearchKey

ABPersonMultiValueDeletes table
カラム名 データ型 コメント
person_id INTEGER ABPerson.ROWID で連絡先を特定.
value BLOB 連絡先を検索するための検索キー

valueカラムに格納される値は ABPerson.{First|Last}Sortカラムとよく似たエンコーディングで FirstPhonetic, LastPhonetic, First, Last, Organization を変換した結果(バイナリデータ)である. このエンコーディングは以下の通り.

8.1 SearchKeyのエンコーディング

ABPersonSeachKey.valueカラムには(1)FirstPhonetic,(2)LastPhonetic,(3)First, (4)Last, (5)Organizationを以下の規則でエンコードしたものを,0x02で区切ってつなげた値を保持する.未定義のフィールドはスキップする

  • 空白文字の場合,(0x02)の1バイトに変換(0x02はフィールドのセパレータらしい).
  • 数字の場合,(0x29), (0x7c+数値) の2バイトに変換.
  • アルファベットの場合,大文字に変換した上で「ABC...XYZ」26文字中の順位をN (N=0..25) として,(0x2c+2N)の1バイトに変換.
  • ひらがな・カタカナの場合,濁音・半濁音を取り除き,小文字(ぁぃぅぇぉっゃゅょ)は大文字に変換した後,「あいうえおかきくけこ...らりるれろわゐゑをん」50音中の順位をN (N=0..) として,(0xa3), (0x20+2N) の2バイトに変換.
  • 漢字の場合,JISコードの区点コードをA区B点として,C=94A+Bを求める.
    • C < 1516の時(つまり16区1点「亜」から16区11点「茜」までの11文字)は,(C-1318)の1バイトに変換.
    • C \ge 1516の時は,C + 5 \left\lfloor C/251 \right\rfloor + 0xc604を求めて,その上位バイト,下位バイトの2バイトに変換する.

9 ABPhoneLastFour

ABPhoneLastFour table
カラム名 データ型 コメント
multivalue_id INTEGER 電話番号を保持しているABMultiValueを参照するforeign key (primary keyでもある)
value TEXT 電話番号の下4桁

このテーブルに電話番号の下4桁を登録しておくと,通話履歴,SMS/MMS, 着信時に連絡先の名前を表示してくれる.

10 ABRecent

未調査

11 ABStore

未調査

12 FirstSortSectionCount

未調査

13 LastSortSectionCount

未調査

14 _SqliteDatabaseProperties

_SqliteDatabaseProperites table
カラム名 データ型 コメント
key TEXT 属性名 (primary key)
value TEXT 属性値

データベースが初期化された際に,次のような値が格納される.

key value コメント
SortingcacheLanguage ja 日本語の場合
SortingCacheICUVersion 67108864 ICUライブラリのバージョン?
SortingCacheVersion 12 キャッシュのバージョン?
_ClientVersion 16 クライアントのバージョン?
_UniqueIdentifier 16進数 8桁-4桁-4桁-4桁-12桁 初期化されるたびに異なる値が生成される