ホーム > デベロッパ > SophiaFramework > BREW C++ 逆引きコード集

BREW C++ プログラミング 逆引きコード集 : ストリーム

C++ で作成されたBREW アプリで、ストリームを扱う方法です。
SophiaFramework を用いています。

BREW コールバック関数の登録と呼び出し(JPEG 画像データを読み込んで表示する方法)

BREW ネイティブのコールバック関数を登録し、呼び出すためのサンプルコードです。

ファイルストレージまたはメモリストレージに保存された JPEG 画像データを読み込んで表示するコードを以下に記します。

BREW の仕様では、JPEG 画像データの表示処理は、ファイルストレージまたはメモリストレージに保存された JPEG 画像データの読み込みが完了したときに呼び出されるコールバック関数内に記述する必要があります。

ファイルストレージまたはメモリストレージに保存された JPEG 画像データを読み込むためのストリームは、 SFBImage::SetStream() 関数を使って設定します。

コールバック関数は SFBImage::Notify() 関数を使って登録します。

なお、コールバック関数を登録する SFBImage 型のインスタンス変数は jpegreader クラスの変数として登録します。メンバ関数などローカル変数として登録すると、スマートポインターで管理されるため変数スコープから外れたときに、メモリは自動的に解放され、コールバック関数が呼び出されません。

また、コールバック関数の実体は、ダミーのコールバック関数内から呼び出されます。コールバック関数の登録では、ダミーのコールバック関数を登録します。

■クラスの定義

SFMTYPEDEFCLASS(jpegreader)
class  : public SFYApplication {
    SFMSEALCOPY(jpegreader)
private:
    SFBImageSmp _image;
public:
    static SFCInvokerPtr Factory(Void);
private:
    explicit jpegreader(Void) static_throws;
    virtual ~jpegreader(Void);
    SFCError LoadImage(SFXPathConstRef path);
    SFCError ExampleDirectFile(SFXFilePtr file); 
    SFCError ExampleThroughMemory(SFXFilePtr file, UInt32 size);
    XANDLER_DECLARE_BOOLEVENT(OnKey)
   
    // コールバック関数の実体
    Void OnImage(Void);  
    // ダミーのコールバック関数
    friend Void read_finished(VoidPtr, IImage*, AEEImageInfo*, SIntN);  
};

※注意:
1.JPEG 画像データを読み込む変数 _image は、クラス変数として定義します。JPEG 画像データを読み込むためのメンバ関数 LoadImage() 内のローカル変数として定義すると、JPEG 画像データの読み込み完了時に自動的に解放されるため、JPEG 画像を表示するためのダミーのコールバック関数 read_finished() が呼び出されません。

2.JPEG 画像を表示するためのダミーのコールバック関数 read_finished()は、friend 関数として定義します。

3.JPEG 画像を表示する実際の処理は、jpegreader::OnImage() 関数に記述します。このメンバ関数は、ダミーのコールバック関数 read_finished() から呼び出されます。

■クラスの実装

// パスから JPEG 画像データを読み込む
SFCError jpegreader::LoadImage(SFXPathConstRef path)
{
    SFXFile   file;
    UInt32    size;
    SFCError  error(SFERR_NO_ERROR);

    if ((_image = SFBImage::NewInstance(AEECLSID_JPEG, &error)) != null) {

        if ((error = file.OpenReadOnly(path)) == SFERR_NO_ERROR) {

            if ((error = file.GetSize(path, &size)) == SFERR_NO_ERROR) {

                // ファイルストレージから JPEG 画像を読み込む場合
                // ExampleDirectFile(&file);  

                // メモリストレージから JPEG 画像を読み込む場合
                ExampleThroughMemory(&file, size);
             }
        }
    }
    return error;
}

// ファイルストレージから JPEG 画像データを読み込む
SFCError jpegreader::ExampleDirectFile(SFXFilePtr file)
{
    // ダミーのコールバック関数を登録する
    _image->Notify((PFNIMAGEINFO)read_finished, this);

    // ファイルストレージのストリームを設定する
    return _image->SetStream(*file);
}

// メモリストレージから JPEG 画像データを読み込む
SFCError jpegreader::ExampleThroughMemory(SFXFilePtr file, UInt32 size)
{
    SFXBuffer  buffer;
    VoidPtr    ptr;
    SFXMemory  memory;
    SFCError   error(SFERR_NO_ERROR);

    if (size > 0) {

        if ((error = buffer.SetSize(size)) == SFERR_NO_ERROR) {

            ptr = buffer.Detach();

            if ((error = file->Read(ptr, &size)) == SFERR_NO_ERROR) {

                if ((error = buffer.Attach(ptr, size)) ==SFERR_NO_ERROR) {

                    if ((error = memory.Open(buffer)) == SFERR_NO_ERROR) {

                        // ダミーのコールバック関数を登録する
                        _image->Notify((PFNIMAGEINFO)read_finished, this);

                        // メモリストレージのストリームを設定する
                        error = _image->SetStream(memory);
                    }
                }
            }
        }
    }
    else {
        error = SFERR_FAILED;
    }
    return error;
}

// 実際のコールバック関数(実体:  JPEG 画像を描画する)
Void jpegreader::OnImage(Void)
{
    SFXRectangle  rx;
    AEEImageInfo  info;

    rx.Set(GetLocalBound());

    _image->GetInfo(&info);

    //  JPEG 画像を描画する
    _image->Draw((rx.GetWidth()-info.cx)/2, (rx.GetHeight()-info.cy)/2);

    return;
}

// ダミーのコールバック関数(PFNIMAGEINFO 型)
Void read_finished(VoidPtr reference, IImage* /* image*/, AEEImageInfo* /* info*/, SIntN /* error*/)
{
    // 実際のコールバック関数を呼び出す
    static_cast<jpegreaderPtr>(reference)->OnImage();

    return;
}

※注意:
4.JPEG 画像表示処理の実体は、ダミーのコールバック関数 read_finished() から呼び出される実際のコールバック関数 jpegreader::OnImage() 内に実装します。

5.JPEG 画像データを読み込むためのファイルストレージまたはメモリストレージを SFBImage::SetStream() 関数を使って設定し、SFBImage::Notify() 関数を使ってダミーのコールバック関数 read_finished() を登録します。

サンプルコードダウンロード( jpegreader.zip: 99.7kb )

□関連情報:BREW FAQ : JPEG 形式で保存した画像ファイルを読み込むには

      

gzip による Deflate 圧縮データを解凍する

SFXZIPDecoder クラスを利用して、ストレージ クラスや SFBSourceSFBAStream に格納された gzip による Deflate 圧縮データを解凍します。

// コールバックを使うため、SFXZIPDecoder のインスタンスはクラスのメンバ変数にする
class MyClass {
private:
    SFXFile _file;                      // ファイル クラス のインスタンス
    SFXZIPDecoder _decoder;             // SFXZIPDecoder クラスのインスタンス
    SFXAnsiStringStreamReader  _reader; // 読み込み用ストリーム
    SFXAnsiString _unzipString;         // 解凍後の文字列
public:
    Void Start(Void);

    // コールバック関数
    CALLBACK_DECLARE_SFXANSISTRINGSTREAMREADER(OnFetch)
};

Void MyClass::Start(Void)
{
    SFCError error; // エラー

    // 読み書きモードでファイルを開く
    if ((error = _file.OpenReadOnly(SFXPath("/testdata.tar.gz")))
        == SFERR_NO_ERROR) {

        // ストレージ ( ファイル ) をデコーダに登録する
        if ((error = _decoder.Open(_file)) == SFERR_NO_ERROR) {

            // デコーダから読み込み用ストリームを取得する
            if ((error = _decoder.GetStreamReader(&_reader))
                == SFERR_NO_ERROR) {

                // フェッチする
                if ((error = _reader.Fetch(CALLBACK_FUNCTION(OnFetch)))
                    != SFERR_NO_ERROR) {
                    // エラーのとき
                    _reader.Release();
                }
            }
            if (error != SFERR_NO_ERROR) { 
                // エラーのとき
                _decoder.Close();
            }
        }
        if (error != SFERR_NO_ERROR) { 
            // エラーのとき
            _file.Close();
        }
    }
}

// フェッチが完了したときに呼び出されるコールバック関数
CALLBACK_IMPLEMENT_SFXANSISTRINGSTREAMREADER(MyClass, OnFetch, error)
{
    if (error == SFERR_NO_ERROR) {  
        // エラーが発生していないとき

        // 解凍したデータを _unzipString 変数に読み込む
        if ((error = _reader.ReadSFXAnsiString(&_unzipString)) == SFERR_NO_ERROR) {

            // 文字列を表示する
            TRACE("%s", _unzipString.GetCString());
        }
    }
    // 終了処理
    _decoder.Close();
    _file.Close();
}
      

ISource インターフェースからデータを読み込む

SFXSource クラスを利用して、ISource インターフェースからデータを読み込みます。

SFXSource source; 
static ACharConst data[] = "test data"; // 読み込むデータ
SFXAnsiString string;           // 書き込むデータ
SFXBinaryStreamReader reader;   // メモリ読み込み用ストリーム
SFBSourceUtilSmp util;
SFBSourceSmp bs;

// メモリブロックから SFBSource を作成する
util = SFBSourceUtil::NewInstance();
util->SourceFromMemory(data, sizeof(data), null, null, &bs);

// ストレージを開く
if (source.Open(bs) == SFERR_NO_ERROR) {

    // メモリ読み込み用ストリームを取得する
     if (source.GetStreamReader(1024, &reader) == SFERR_NO_ERROR) {

        reader.Fetch();  // フェッチする ( データを読み込む ) 
        reader >> string; // ストリームにデータを読み込む

        // 文字数を取得する size = 9
        TRACE("size = %d", string.GetLength());   
        // 内部バッファを取得する read = test data   
        TRACE("read = %s", string.GetCString());  

        reader.Release();  // ストリームを解放する
    }
    source.Close();  // メモリ ストレージを閉じる
}
      

内部バッファで読み書きを行う

SFXMemory クラスを利用して、内部バッファを読み書きします。

SFXMemory memory;
SFXBinaryStreamWriter writer;   // メモリ書き込み用ストリーム 
SFXBinaryStreamReader reader;   // メモリ読み込み用ストリーム
SFXAnsiString string;           // 書き込むデータ

// メモリ ストレージを開く
if (memory.Open() == SFERR_NO_ERROR) {

    // メモリ書き込み用ストリームを取得する
    if (memory.GetStreamWriter(1024, &writer)== SFERR_NO_ERROR) {

        writer << "abc";  // ストリームにデータを書き込む
        writer.Flush();   // フラッシュする(実際にデータを書き込む)

        // バッファ サイズを取得する size = 4
        TRACE("size = %d", memory.GetSize());    
        // 内部バッファへのポインターを取得する write = abc + '\0'
        TRACE("wrire = %s", memory.GetBuffer()); 
        
        writer.Release();  // ストリームを解放する
    }

    // 先頭へシークする
    memory.SeekStart(0);

    // メモリ読み込み用ストリームを取得する
    if (memory.GetStreamReader(1024, &reader) == SFERR_NO_ERROR) {

        reader.Fetch();  // フェッチする ( データを読み込む ) 
        reader >> string; // ストリームにデータを読み込む

        // 文字数を取得する size = 3
        TRACE("size = %d", string.GetLength());   
        // 内部バッファを取得する read = abc
        TRACE("read = %s", string.GetCString());  

        reader.Release();  // ストリームを解放する
    }
    memory.Close();  // メモリ ストレージを閉じる
}
      

ANSI 文字列のストリームから WIDE 文字列を作成する

ANSI 文字列のストリームから WIDE 文字列を効率よく作成する例

UInt32 length;
SFXBinaryStreamReader stream;
SFXBuffer buffer;
SFXAnsiString ansi;
SFXWideString wide;
SFCError error(SFERR_NO_ERROR);

length = 10; // for test

// ストリームから読み込むためのバッファを確保する
// 文字列クラスへのバッファの委譲では、最後の文字にあたる
// バッファはヌル文字で上書きされる
//  +1 が必要
if ((error = buffer.SetSize(length + 1)) == SFERR_NO_ERROR) {

    // ストリームから ANSI 文字列を読み込む
    if ((error = stream.Read(buffer.GetBuffer(), length)) == SFERR_NO_ERROR) {

        // 最後の文字をヌル終端する
        buffer[length] = '\0';

        // ansi 変数にバッファを委譲する
        if ((error = ansi.AttachSFXBuffer(&buffer)) == SFERR_NO_ERROR) {

            // ANSI 文字列から WIDE 文字列へ変換する
            if ((error = wide.Set(ansi)) == SFERR_NO_ERROR) {

                // wide 変数は有効
                // この例ではバッファのコピーは2回
            }
        }
    }
}
      

ファイルの終端を検知する

バージョン 4.0 以降

ファイルからデータを読み取るストリームでファイルの終端を検知するには、
SFXStreamReader::Ends 関数を使用します。

以下のコードは、ファイルから終端に達するまで1文字ずつ読み込み、表示します。

SFXFile file;
SFXBinaryStreamReader reader;

if (file.OpenReadOnly(SFXPath("/data.txt")) == SFERR_NO_ERROR) {
    // ファイルのオープンに成功したなら
    UInt08 c;
    file.GetStreamReader(10, &reader);

    while (!reader.Ends()) { // ファイルの終端に到達するまで
        if (reader.GetReadableSize() == 0) {
            reader.Fetch();
        }
        reader >> c;      // 1文字読み込み
        TRACE("%c", c);   // 表示
    }
    file.Close();
}

バージョン 3.0

ファイルストリームでファイルの終端を検知するには、
SFUFileStream::IsEOS 関数を使用します。

以下のコードは、ファイルから終端に達するまで1文字ずつ読み込み、表示します。

SFUFileStream fstream;

if (fstream.Open("/data.txt", _OFM_READ) == SFERR_NO_ERROR) {
    // ファイルのオープンに成功したなら
    AChar c;

    while (!fstream.IsEOS()) { // ファイルの終端に到達するまで
        fstream >> c;      // 1文字読み込み
        TRACE("%c", c);    // 表示
    }
    fstream.Close();
}

参照 SFXFile::OpenReadOnly | SFXFile::GetStreamReader |
SFXStreamReader::GetReadableSize | SFXStreamReader::Fetch

      

ファイルから読み込みを行う

バージョン 4.0 以降

ファイルから読み込みを行うには、ファイルクラスから入力ストリームを
取得し、ストリームから読み込みを行います。

SFXFile file;
SFXAnsiStringStreamReader reader;
SFXAnsiString temp;
SFXAnsiString string;   // 読み出した文字列を格納
SFXPath path("/data.txt");  // ファイル名

// ファイルオープン
if (file.OpenReadOnly(path) == SFERR_NO_ERROR) {
    // ファイルオープンに成功した
    
    // 入力ストリームの取得
    file.GetStreamReader(1024, &reader);
    while (!reader.Ends()) { // ファイルの終端まで
        if (reader.GetReadableSize() == 0) {
            reader.Fetch();
        }
        reader >> temp; // ファイルからデータを読み出す
        string += temp;
    }
    file.Close();
}

バージョン 3.0

ファイルから読み込みを行うには、ファイルストリームクラス SFUFileStream
使用します。

SFUFileStream fstream;
SFXAnsiString string;   // 読み出した文字列を格納
SFXAnsiString filename("/data.txt");

// ファイルオープン
if (fstream.Open(filename, _OFM_READ) == SFERR_NO_ERROR) {
    // ファイルオープンに成功した
    fstream >> string; // ファイルから全データを読み出す
    fstream.Close();
}

参照 SFXFile::OpenReadOnly | SFXFile::GetStreamReader |
SFXStreamReader::GetReadableSize | SFXStreamReader::Fetch

      

ファイルに書き込みを行う

バージョン 4.0 以降

ファイルから書き込みを行うには、ファイルクラスから出力ストリームを
取得し、ストリームに書き込みを行います。

SFXFile file;
SFXAnsiStringStreamWriter writer;
SFXAnsiString string("abcdefg"); // 書き込む文字列
SFXPath path("/data.txt"); // ファイル名

// ファイルオープン
if (file.OpenReadWrite(path) == SFERR_NO_ERROR) {
    // ファイルオープンに成功した
    
    // 出力ストリームの取得
    file.GetStreamWriter(string.GetLength(), &writer);
    writer << string;
    writer.Flush();
    file.Close();
}

バージョン 3.0

ファイルに書き込みを行うには、ファイルストリームクラス SFUFileStream
使用します。

SFUFileStream fstream;
SFXAnsiString string("abcdefg");      // 書き込む文字列
SFXAnsiString filename("/data.txt");     // ファイル名

//ファイル新規作成
if (fstream.Open(filename, _OFM_CREATE) == SFERR_NO_ERROR) {
    // 新規作成に成功したなら
    fstream << string;                 // ファイルに書き込み
    fstream.Close();
}

参照 SFXFile::OpenReadWrite | SFXFile::GetStreamWriter |
SFXStreamWirter::Flush