Apple Developer Connection
Advanced Search
Member Login Log In | Not a Member? Contact ADC

< Previous PageNext Page >

データのバイトスワップを行うコールバックの作成

カスタムリソースデータ、カスタムペーストボードデータ、カスタムアップルイベントデータを対象とした、フリッパーと呼ぶこともあるバイトスワップ用のコールバックルーチンをシステムに対して提供することが可能です。バイトスワップコールバックをインストールするときは、対象データタイプがどのドメインに属するかを指定します。データドメインは、アップルイベントとリソースの2つがあります。リソースデータドメインは、カスタムのペーストボードデータまたはカスタムのリソースデータを示します。コールバックを(アップルイベントとリソースの)どちらのドメインにも適用できる場合、そのように指定することも可能です。

Core Endian APIには、カスタムリソースとカスタムアップルイベントデータのバイトをスワップするために用意するコールバックが定義されています。バイトをスワップするデータタイプごとに1つのコールバックを用意する必要があります。CoreEndianFlipProcコールバックのプロトタイプは次のとおりです。

typedef CALLBACK_API (OSStatus, CoreEndianFlipProc)
    (OSType dataDomain,
    OSType dataType,
    short id,
    void *dataPtr,
    UInt32 dataSize,
    Boolean currentlyNative,
    void *refcon
);

このコールバックは、次のパラメータを受け取ります。

コールバックは、バイトが正常にスワップされたかどうかを示す結果コードを返します。データのバイトスワップがエラーなしに行われた場合、コールバックから noErr を返し、エラーがあった場合にはエラー状況を示す適切な結果コード(errCoreEndianDataTooShortForFormaterrCoreEndianDataTooLongForFormat、または errCoreEndianDataDoesNotMatchFormat)を返します。結果コードは、適切なマネージャ(Resource Manager (ResError)またはApple Event Manager)を通して呼び出し元に伝えられます。

数値でない単位(文字列、バイトストリームなど)のバイトをスワップする必要がありません。バイトスワップのコールバックを用意する必要があるのは、ワードまたはlongワードのバイト順序が重要であるデータ型の場合のみです(Unicode文字列の望ましい処理方法については、「Unicodeテキストファイル」を参照してください)。

コールバックの中では、データを含んでいるデータ構造体をたどって、次の項目のバイトをスワップします。

Core Endian APIには、コールバックの操作に使用できる次の関数が用意されています。

例として、Listing 3-7に定義したカスタムのリソースタイプ('PREF')を対象としたコールバックを考えてみます。MyPreferences構造体は、ディスクに環境設定データを格納するために使用します。この構造体には、いくつかの値が含まれており、RGBColorデータ型の2つのインスタンスと、RGBColor値の配列が1つあります。

Listing 3-7  カスタムリソースの宣言

#define kMyPreferencesType      'PREF'
 
struct MyPreferences {
                SInt32          fPrefsVersion;
 
                Boolean         fHighlightLinks;
                Boolean         fUnderlineLinks;
 
                RGBColor        fHighlightColor;
                RGBColor        fUnderlineColor;
                SInt16          fZoomValue;
 
                char            fCString[32];
 
                SInt16          fCount;
                RGBColor        fPalette[];
};

Listing 3-8に示すMyRGBSwap関数のように、RGBColorデータ型は、RGBColorデータ構造体内のバイトをスワップする関数を作成することで処理できます。この関数は、Core EndianマクロのEndianS16_Swapを呼び出してRGBColor構造体内のそれぞれの値のバイトをスワップします。この関数は、現在実行を行っているシステムを確認する必要はありません。なぜなら、この関数は、RGBColorデータ型の値のバイトスワップを行う必要がない限り、呼び出されることは決してないからです。MyRGBSwap関数は、カスタムの'PREF'リソース(Listing 3-7に定義されています)を処理するために用意されているバイトスワップコールバックルーチン(Listing 3-9に示します)から呼び出されます。

Listing 3-8  RGBColorデータを対象とするフリッパー関数

static void MyRGBSwap (RGBColor *p)
{
    p->red = Endian16_Swap(p->red);
    p->blue = Endian16_Swap(p->blue);
    p->green = Endian16_Swap(p->green);
}

Listing 3-9に、カスタムの'PREF'リソースを対象とするバイトスワップコールを示します。コードの各行番号に対応した説明をリストの後に示します。このフリッパーは、データの形式が正しいかどうか、また、長さが予期しているとおりかを確認している点に注目してください。フリッパールーチンに渡されたデータが、バイトスワップ対象のタイプの通常の長さよりも短い場合、あるいは、(たとえば)配列カウントの代わりに無意味なデータが含まれていた場合、フリッパーの中で渡されたデータの末尾を越えてデータの読み書きを行わないように注意する必要があります。そして代わりに、エラーを返します。

Listing 3-9  カスタムの'PREF'リソースに対するフリッパー

#define kCurrentVersion    0x00010400
 
static OSStatus MyFlipPreferences (OSType dataDomain,  // 1
                    OSType dataType,   // 2
                    short id,   // 3
                    void * dataPtr,   // 4
                    UInt32 dataSize,   // 5
                    Boolean currentlyNative,  // 6
                    void* refcon)  // 7
{
    UInt32  versionNumber;
 
    OSStatus status = noErr;
    MyPreferences* toFlip = (MyPreferences*) dataPtr;       // 8
    int count, i;
 
    if (dataSize < sizeof(MyPreferences))
        return errCoreEndianDataTooShortForFormat;  // 9
    if (currentlyNative)   // 10
    { 
        count = toFlip->fCount;
        versionNumber = toFlip->fPrefsVersion;
        toFlip->fPrefsVersion = Endian32_Swap (toFlip->fPrefsVersion);
        toFlip->fCount = Endian16_Swap (toFlip->fCount);
        toFlip->fZoomValue = Endian16_Swap (toFlip->fZoomValue);
    }   
    else   // 11
    {
        toFlip->fPrefsVersion = Endian32_Swap (toFlip->fPrefsVersion);
        versionNumber = toFlip->fPrefsVersion;
        toFlip->fCount = Endian16_Swap (toFlip->fCount);
        toFlip->fZoomValue = Endian16_Swap (toFlip->fZoomValue);
        count = toFlip->fCount;
    }
    if (versionNumber != kCurrentVersion)  // 12
                return errCoreEndianDataDoesNotMatchFormat;
 
    MyRGBSwap (&toFlip->fHighlightColor);  // 13
    MyRGBSwap (&toFlip->fUnderlineColor);  // 14
 
    if (dataSize < sizeof(MyPreferences) + count * sizeof(RGBColor))
        return errCoreEndianDataTooShortForFormat;   // 15
 
    for(i = 0; i < count; i++)
    {   
        MyRGBSwap (&toFlip->fPalette[i]);  // 16
    }
 
    return status;     // 17
}

このコードが実行することを以下に示します。

  1. システムからコールバックに対して、コールバックの対象となるドメインが渡されます。このドメインは、CoreEndianInstallFlipper関数を使用してコールバックを登録するときに定義します。

  2. システムからコールバックに対して、対象データについて定義したリソースタイプが渡されます。この例では、リソースタイプは'PREF'です。

  3. システムからコールバックに対して、対象データタイプのリソースIDが渡されます。データがリソースでない場合、この値は0です。

  4. システムからコールバックに対して、バイトスワップの対象となるリソースデータへのポインタが渡されます。この例では、ポインタはMyPreferencesデータ構造体を参照します。

  5. システムからコールバックに対して、前のステップで指定されたポインタが指すデータのサイズが渡されます。

  6. コールバックに渡されたバッファ内のデータが、現在実行されているコードのバイト順序と同じ場合、システムからコールバックに対してtrueが渡されます。PowerPC Macintoshでは、currentlyNativetrueの場合、データのバイト順序はビッグエンディアンです。インテルマイクロプロセッサ搭載のMacintoshでは、currentlyNativetrueの場合、データのバイト順序はリトルエンディアンです。コールバックはこの値を知っている必要があります。なぜなら、コールバックの中で、データバッファ内のある値(たとえば、コード例の中のcountなど)を使用して、バッファ内の他のデータの処理方法を決める場合、その値を使用する前に、値のバイトをスワップする必要があるかどうかを知る必要があるからです。

  7. システムからコールバックに対して、アプリケーション固有のデータへのポインタが渡されます。この例では、コールバックはアプリケーション固有のデータを必要としません。

  8. MyPreferencesデータ型に対する変数を定義し、新しく定義したその変数、toFlipに、データポインタの内容を代入します。

  9. 構造体の静的な部分の長さを確認します。本来あるべき長さよりもサイズが小さいと、ルーチンからerrCoreEndianDataTooLongForFormatエラーが返されます。

  10. currentlyNativetrueの場合、countの値をローカル変数に保存し、MyPreferencesデータ構造体内の他の値のバイトスワップを行います。countの値は、関数の中で後で行う反復処理に使用するので、スワップを行う前に保存しておく必要があります。currentlyNativetrueであるという事実は、値を現在実行中のコードの中で使う場合には、値をバイトスワップする必要がないことを示します。しかし、値をディスクの格納する場合にはスワップを行う必要があります。

    これらの値は、適切なCore Endianマクロを使ってスワップします。

  11. currentlyNativefalseの場合には、countの値をローカル変数に保存する前に、MyPreferencesデータ構造体内の値のバイトスワップを行います。currentlyNativefalseであるという事実は、countの値をコールバックの中で使う前にそのバイトをスワップする必要があることを示します。

  12. データ構造体のバージョンが、アプリケーションにサポートされていることを確認します。サポートされていなければ、コールバックはデータのバイトをスワップせず、errCoreEndianDataDoesNotMatchFormatを結果として返します。

  13. MyRGBSwap関数(Listing 3-8参照)を呼び出して、データ構造体のfHighlightColorフィールドのバイトをスワップします。

  14. MyRGBSwap関数を呼び出して、データ構造体のfUnderlineColorフィールドのバイトをスワップします。

  15. データのサイズが、あるべきサイズより小さいことを確認します。小さくなければ、ルーチンはerrCoreEndianDataTooLongForFormatエラーを返します。

  16. fPalette配列内の要素を対象に、反復処理でMyRGBSwap関数を呼び出して、配列内のデータのバイトをスワップします。

  17. データのバイトスワップがエラーなしで行われたことを示すためにnoErrを返します。

このサンプルでは、エラー検査を行いますが、持つことのできるエラー処理コードのすべては含まれていません。実際にフリッパーを作成する際には、そうしたコードは含めるべきでしょう。

注: このコールバックでは、MyPreferencesデータ構造体内のBoolean値のバイトスワップは行いません。なぜならBoolean値は単一の文字値だからです。このコールバックは、C文字列も無視します。

バイトスワップコールバックルーチンの登録は、CoreEndianInstallFlipper関数を呼び出すことで行います。コールバックは、アプリケーションが初期化ルーチンを呼び出したとき、あるいは、リソースを開いたときに登録するようにします。たとえば、Listing 3-9に示したフリッパーコールバックは、次のコードを使って登録します。

OSStatus status = noErr;
status = CoreEndianInstallFlipper (kCoreEndianResourceManagerDomain,
                        kMyPreferencesType,
                        MyFlipPreferences,
                        NULL);

システムは、リソースのロード時にcurrentlyNativefalseであった場合、および、リソースの書き出しの準備ができたときにtrueであった場合に、指定されたリソースタイプに対応するコールバックを呼び出します。たとえば、サンプルとして示したバイトスワップコールバックは、アプリケーションの中で次のコードが実行されるたびに呼び出されます。

MyPreferences** hPrefs = (MyPreferences**) GetResource ('PREF',  128);

データのバイトスワップ後は、必要に応じていくらでもデータに変更を加えることができます。

Resource Managerはディスクからリソースを読むとき、バイトスワップルーチンのテーブルの中でリソースタイプ(たとえば、'PREF')の照会を行います。当該リソースタイプに対応するコールバックがインストールされていれば、Resource Managerはコールバックを呼び出します。Resource Managerがリソースをディスクに書き出すときにも同様の処理が行われます。Resource Managerは適切なルーチンを探し、リソースのバイトをビッグエンディアンのバイト順序にスワップするためにコールバックを呼び出します。

ペースボードデータに対応するコールバックがインストールされているアプリケーションからカスタムのデータをコピーまたはドラッグすると、システムはインストールされているコールバックを適切なタイミングで呼び出します。カスタムのデータをネイティブアプリケーションにコピーまたはドラッグすると、データコールバックは呼び出されません。カスタムのデータをネイティブでないアプリケーションにコピーまたはドラッグすると、システムは該当コールバックを呼び出してカスタムデータのバイトをスワップします。ネイティブでないアプリケーションからカスタムのデータを対象アプリケーションにペーストまたはドロップすると、当該カスタムデータに対応するコールバックが存在すれば、システムはペースト時またはドロップ時にコールバックを呼び出します。カスタムデータが別のネイティブアプリケーションからコピーまたはドラッグされてきた場合、コールバックは呼び出されません。

各ペースボードAPIは、それぞれに異なる型指定子を使います。Scrap ManagerとDrag ManagerはOSTypeデータ型を使います。Pasteboard ManagerはUniform Type Identifier (UTI)を使い、NSPasteboardクラスは独自の型指定を使います。いずれの場合も、当該の型に対応するバイトスワップコールバックの有無を確認するために、型がシステムによってOSTypeデータ型に変換されます。

アップルイベントデータタイプは通常、ネットワーク経由で送信されるときにネットワークバイト順序にスワップされます。インストールしたコールバックは、独自に定義したカスタムデータタイプを別のマシンに送信するとき、あるいは、別のマシンから対象アプリケーションにアップルイベントデータが送信されてきたときにのみ呼び出されます。ネットワーク上でのアップルイベントのバイト順序はビッグエンディアンです。

システムが通常ならバイトスワップコールバックを呼び出さないような場合でも、CoreEndiaFlipData 関数を呼び出して、特定のデータ型とドメインに対してインストールされているコールバック関数を呼び出せます。



< Previous PageNext Page >


Last updated: 2006-03-08




Did this document help you?
Yes: Tell us what works for you.

It’s good, but: Report typos, inaccuracies, and so forth.

It wasn’t helpful: Tell us what would have helped.
Get information on Apple products.
Visit the Apple Store online or at retail locations.
1-800-MY-APPLE

Copyright © 2007 Apple Inc.
All rights reserved. | Terms of use | Privacy Notice