高度な検索
Developer Connection
Member Login ログイン | ご入会 ADC連絡先

Technical Q&A QA1410
Using language-tagged QuickTime UserData text APIs with CFStrings

Q:AddUserDataText を使用しているときに、日本語版 OS を対象とした UTF-8 テキストを追加すると、いつも意外な結果を得ます。この API はテキスト文字列と言語コード(itlRegionTag)を受け取ると説明されていますが、UTF-8 文字列を正しい言語にマップするにはどうすればよいでしょうか。CFStrings だけで処理が済むのが理想です。

A:AddUserDataTextGetUserDataText など、テキスト文字列を受け取ったり返したりする多くの QuickTime API は、テキスト文字列が Traditional Mac OS 言語固有のエンコード(kTextEncodingMacJapanese など)の 1 つであると仮定しています。そのため、これらの API 渡す itlRegionTag パラメータの値は言語コード(langJapanese など)である必要があります。

使用する文字列が UTF-8(または UTF-16)の場合は、AddUserDataText を使用するときに、文字列を適切な Traditional Mac OS 言語固有のエンコードに変換する必要があります。

CFString には、CFStringGetBytes を呼び出して適切な CFStringEncoding に渡すことで、この変換を実行できる機能があります。

注意:CFStringEncoding は、さまざまな CFString 関数においてサポートしている文字列エンコードを指定するのに使用する整数型の定数です。その値は Text Encoding Converter の TextEncoding 型とまったく同じで、TextCommon.h に含まれています。

Traditional Mac OS 言語コードを CFStringGetBytes の適切な TextEncoding にマップするには、従来の Mac OS スクリプトコード、言語コード、およびリージョンコードの組み合わせを TextEncoding に変換する GetTextEncodingFromScriptInfo を呼び出します。

リスト 1 には、上記の方法を使用して、CFString からユーザデータテキスト項目を追加する方法を示します。一方、リスト 2 には、テキストユーザデータ項目を CFString として取得する方法を示します。QuickTime は言語タグ付きテキストを必要とするため、これらの UserData API では、Script.h に含まれる Traditional Mac OS 言語コードを必ず使用する必要があります。

注意:変換がいつも可能なわけではない点に注意してください。たとえば、日本語とアラビア語が混在する CFString の場合には、いかなる単一の Traditional Mac OS エンコードにも変換できません。不可逆変換を実行しないかぎり、この変換は失敗します。CFStringGetBytes では、「欠損バイト」を関数に渡すことで不可逆変換が可能です。文字を変換できないと、CFStringGetBytes はそれを「欠損バイト」で置き換え、変換を続行します。

詳細については、「Converting Between String Encodings」を参照してください。

リスト 1:言語コードを使用して UserData 項目をテキストとして追加

/* AddUserDataTextFromCFString
 *
    説明:
       CFString からユーザデータ項目をテキストとしてユーザデータリストに追加する。
       そのために、可能な場合は Traditional Mac OS エンコードを使用して
       実装された指定の言語への文字変換を実行する。
     
       パラメータ:
       inUserData     - この操作の対象となるユーザデータリスト
       inUDType       - 新しい項目に割り当てられる型
       inIndex        - テキストを追加する対象となる項目
       inLanguageCode - 特定の Mac OS エンコード(langEnglish、langJapanese など)を使用して実装された言語コード
       inCFString     - 追加するユーザデータを含む CFString
    
       戻り値:
        noErr または障害発生時は適切なエラーコード
 *
 */
OSStatus AddUserDataTextFromCFString(UserData inUserData, SInt32 inUDType, SInt32 inIndex,
                                     SInt16 inLanguageCode, CFStringRef inCFString)
{
    // コピーする文字の文字列エンコード、
    // 値は Text Encoding Converter TextEncoding と同じ
    CFStringEncoding encoding = 0;
    CFIndex numberOfCharsConverted = 0, usedBufferLength = 0;
    CFRange range = { 0, CFStringGetLength(inCFString)};
    OSStatus status;
    
    // Mac OS スクリプトコード、言語コード、リージョンコードの任意の組み合わせを
    // テキストエンコードに変換
    // 渡される CFString はこのエンコードである必要がある
    status = GetTextEncodingFromScriptInfo(kTextScriptDontCare, inLanguageCode,
                                           kTextRegionDontCare, &encoding);
    if (noErr == status) {
       // 文字を指定エンコードに変換した後で、CFString オブジェクトの文字を
       // バイトバッファにグラブ
       // まず、確実に変換できることを確認するために、対象バッファに NULL を渡し、
       // 次に、不可逆変換を使用しないので、文字列全体を確実に変換できることを
       // 確認する
       numberOfCharsConverted = CFStringGetBytes(inCFString, range, encoding, 0, false,
                                                 NULL, 0, &usedBufferLength);
        if ((numberOfCharsConverted == CFStringGetLength(inCFString)) && (usedBufferLength > 0)) {
            // 変換できることが確認されたので、今度は実際の変換を行う
            Handle hData = NewHandleClear(usedBufferLength);
            if (NULL != hData) {
                HLock(hData);
            
                numberOfCharsConverted = CFStringGetBytes(inCFString, range, encoding, 0,
                                                        false, *hData, usedBufferLength,
                                                        &usedBufferLength);
                status = AddUserDataText(inUserData, hData, inUDType, inIndex,
                                      inLanguageCode);

                DisposeHandle(hData);
            } else {
                status = MemError();
            }
        } else {
            // 変換できない
            status = kTextUnsupportedEncodingErr;
        }
    }
    
    return status;
}

リスト 2:言語タグ付き UserData テキストを CFString として取得

/* GetUserDataTextAsCFString
 *
    説明:
        ユーザデータリストの項目から言語コードタグ付きテキストを CFString として取得する。
        そのために、可能な場合は、適切なテキストエンコードへの
        文字変換を実行する
          
    パラメータ:
    inUserData     - この操作の対象となるユーザデータリスト
    inUDType       - 新しい項目に割り当てられる型
    inIndex        - テキストを追加する対象となる項目
    inLanguageCode - 特定の Mac OS エンコード(langEnglish、langJapanese など)を使用して実装された言語コード
    
    戻り値:
       テキスト、または障害発生時には NULL を含む CFString
    
    注意:
       返された CFString は、呼び出し側の責任で解放する
 *
 */
CFStringRef GetUserDataTextAsCFString(UserData inUserData, SInt32 inUDType, SInt32 inIndex,
                                      SInt16 inLanguageCode)
{
    TextEncoding encoding = 0; // バッファ内の文字のエンコード
    CFStringRef string = NULL;
    Handle hData = NULL;
    OSStatus status;
    
    hData = NewHandle(0);
    if (NULL == hData || noErr != MemError()) return NULL;

    status = GetUserDataText(inUserData, hData, inUDType, inIndex, inLanguageCode);
    if (noErr == status && (GetHandleSize(hData) > 0)) {
        // Mac OS スクリプトコード、言語コード、リージョンコードの任意の組み合わせを
        // テキストエンコードに変換
        status = GetTextEncodingFromScriptInfo(kTextScriptDontCare, inLanguageCode,
                                              kTextRegionDontCare, &encoding);
        if (noErr == status) {
            // バッファから、指定エンコードの文字を含む
            // CFString オブジェクトを作成
            HLock(hData);
            string = CFStringCreateWithBytes(kCFAllocatorDefault, (const char *)*hData,
                                            GetHandleSize(hData), encoding, false);
        }
    }
        
    DisposeHandle(hData);
    
    return string;
}

参考資料

先頭に戻る

ダウンロード

先頭に戻る

ドキュメントの改訂履歴

日付 メモ
2005-02-10 初版

掲載日: 2005-02-10