These pages are written by only Japanese.

Welcom to My Diary.com
最新の日記タイトル一覧カテゴリ別タイトル一覧トップへ戻る〜

こんにちは♪ 現在は4月24日(水)15時9分。 TeaBreakにしましょうか?


hns - 日記自動生成システム - Version 2.19.5 (色々 Fixed)

先月 2008年07月 来月
01 2 3 04 05
06 07 08 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
Namazu for hns による簡易全文検索です。
詳細は 詳細指定/ヘルプをご参照下さい。
検索式:

2008年07月14日(月)

(ファイルでなく)配列変数で PNGデータを libpng に渡す方法

これ の続き
libpng で(ファイルストリームでなく)配列変数から直接PNGデータを 読み書きする方法がようやく分かったので、その顛末。

調査:

libpng の使い方のページを探しても、ファイルポインタを渡すのばかりで メモリオブジェクトを直接渡すサンプルプログラムが殆ど見つかりません。 その上、見つけたモノもオーバーフロウの対策が入ってない(ように見える)ので、 libpng.txt を見直すことにしました。
libpng にある入出力はpng_read() や png_write() を通して処理されます。
現行では fread() や fwrite() を呼ぶだけです。FILE * は png_struct
内部に記憶され、png_init_io() を経由して初期化されます。
I/O 命令を変更したいなら、png_init_io() を呼ぶ代わりに実行時に
png_set_read_fn() と png_set_write_fn() 関数を通してライブラリ指定
のコールバックを設定することができます。
という事ですが、
png_set_read_fn(png_structp read_ptr,
                voidp read_io_ptr, png_rw_ptr read_data_fn)
png_set_write_fn(png_structp write_ptr,
                  voidp write_io_ptr, png_rw_ptr write_data_fn,
                  png_flush_ptr output_flush_fn);
voidp read_io_ptr = png_get_io_ptr(read_ptr);
voidp write_io_ptr = png_get_io_ptr(write_ptr);

void user_read_data(png_structp png_ptr,
                    png_bytep data, png_size_t length);
void user_write_data(png_structp png_ptr,
                     png_bytep data, png_size_t length);
void user_flush_data(png_structp png_ptr);
API群を見てもいまいちピンと来ないので、 「png_set_write_fn」で検索したところ以下のページを発見。
png_get_io_ptrによって、png_set_read_fun/png_set_write_funで与えた引数を
png_ptrで示されるコンテキストオブジェクトから取得できるので、それを
ストリームへのポインタにキャストして仕事をまっとうしているわけです。
あー。なるほど。
libpng.txt にも同じ意味の事が書いてありますが、 こういう説明の仕方でないと自分には分からないのです。^^;
static void png_default_write_data(png_structp png_ptr,png_bytep data,png_size_
t length)
{
        OSErr   err;
        long    llong=length;
        short   refNum=((MyPNGFileRec *)png_ptr->io_ptr)->refNum;

        err=FSWrite(refNum,&llong,data);
        if (err!=noErr)
        {
                png_error(png_ptr,"Write Error");
        }
}
なるほど。なるほど。
コンテキストオブジェクトに汎用ポインタで任意の構造体データを渡せるので 最大長も一緒に渡してカスタム関数でオフセットと長さの比較をすれば、 オーバーフロウを防御できそうです。

テストコード:

typedef struct my_png_buffer_ {
    unsigned char *data;
    unsigned long data_len;
    unsigned long data_offset;
} my_png_buffer;

void png_memread_func(png_structp png_ptr, png_bytep buf, png_size_t size){
    my_png_buffer *png_buff = (my_png_buffer *)png_get_io_ptr(png_ptr);
    if (png_buff->data_offset + size <= png_buff->data_len) {
        memcpy(buf, png_buff->data + png_buff->data_offset, size);
        png_buff->data_offset += size;
    } else {
        png_error(png_ptr,"png_mem_read_func failed");
    }
}

void png_data_read(png_structp png_ptr, my_png_buffer *png_buff) {
    png_set_read_fn(png_ptr, (png_voidp) png_buff,
                    (png_rw_ptr)png_memread_func);
}
こんな感じでいいかな。

結果:

正常なファイル。(3x3 の青い画像)
% ./a.out cyan_3x3.PNG
png_filename=cyan_3x3.PNG
png_buff.data_len=152
(width, height)=(3,3) bpp=8 color_type=2
異常なファイル1 (バッファオーバーフロウ)
% ./a.out cyan_3x3-cut.PNG
png_filename=cyan_3x2-cut.PNG
png_buff.data_len=91
libpng error: png_mem_read_func failed
アボートしました
ファイルの後ろを少し削ったファイルを渡したところ、 長さチェックで弾いてくれました。よしっ。

ついでに:

↑ここで紹介されてた異常なファイル (何かの攻撃用らしい)
% ./a.out pngtest.png
png_filename=pngtest.png
png_buff.data_len=8574
libpng error: PNG unsigned integer out of range.
アボートしました
ふむ。完璧。
続く

swfed 要望

Lossless 対応が一息ついたら、こちらに取り掛かる予定です。

これで、1 日分だよ〜。

タイトル一覧
カテゴリ分類
Database
JXTA
Java
XML
awm
bookmark
keyword
memo
news
research
Powered by hns-2.19.5, HyperNikkiSystem Project