/* kdechunk3.c * チャンク形式データ用デコーダ */ #define USAGE "Usage: kdechunk3 " #include "mystab.h" #include "myio_apr.h" #include "myio_chunk.h" /* * 文字列 s 中に最初ぶ文字 c が現れた位置へのポインタを返す関数 * (strchr 相当) */ char * mystrchr (const char *s, char c) { const char *p = s; if (p) for (; *p; p++) if (*p == c) return (char*)p; return NULL; } /* entity-header が "Transfer-Encoding" ヘッダの時に、 * ヘッダの値が "chunked" か調べるコールバック関数 */ void lookup_te_chunked ( const char *line , void *ctx ) { char *name = NULL; char *value = NULL; char *pos = NULL; int *seen_chunked = (int*)ctx; if (!line || !ctx) return; name = (char*)line; pos = mystrchr(line, ':'); if (!pos) return; /* ':' が見つからなかった時は何もしない。 */ /* ':' の前の空白を検査していないが、本来はすべきだろう。 */ if (strncasecmp(name, "transfer-encoding", pos-name)) { return; } /* ':' の後の空白のスキップ */ pos++; while(*pos && (*pos == ' ' || *pos == '\t')) pos++; value = pos; if (!strcmp(value, "chunked")) { *seen_chunked = 1; if(0)printf("#T-E chunked found.\n"); } } void *my_alloc(void *ctx, int size) { apr_pool_t *pool = (apr_pool_t*)ctx; apr_size_t s = (apr_size_t)size; return apr_palloc(pool, s); } int apr_my_main ( int ac , char **av , apr_file_t * astdin , apr_file_t * astdout , apr_file_t * astderr , apr_pool_t * pool ) { int error_flag = 0; MYIO *in = NULL; MYIO *out = NULL; char *infilename = NULL; char *outfilename = NULL; int chunked = 0; if (ac < 2) { apr_file_printf(astderr, "%s\n", USAGE); goto _FINALLY_; } infilename = av[1]; outfilename = av[2]; in = MYIO_fp_open(infilename, APR_FOPEN_READ|APR_FOPEN_BINARY, APR_OS_DEFAULT, pool); if (! in) { apr_file_printf(astderr, "ERROR: MYIO_fp_open: %s ", infilename); error_flag = 1; goto _FINALLY_; } out = MYIO_fp_open(outfilename, APR_FOPEN_WRITE|APR_FOPEN_CREATE|APR_FOPEN_TRUNCATE|APR_FOPEN_BINARY, APR_OS_DEFAULT, pool); if (! out) { apr_file_printf(astderr, "ERROR: MYIO_fp_open: %s ", outfilename); error_flag = 1; goto _FINALLY_; } /* ヘッダの読み出し。T-E が "chunked" かチェックする。 */ if (MYIO_read_entity_headers_CRLF_do(in, lookup_te_chunked, &chunked) == 0) { apr_file_printf(astderr, "ERROR: MYIO_read_entity_headers_CRLF_do "); error_flag = 1; goto _FINALLY_; } if (chunked) { /* チャンク形式のボディをデコード。デコード結果は標準出力とストリーム out へ */ char buf[80]; int nbytes=0; MYIO *dc_in = NULL; dc_in = MYIO_dechunk_filter_new(in, my_alloc, pool); if (!dc_in) { apr_file_printf(astderr, "ERROR: dechunk_filter "); error_flag = 1; goto _FINALLY_; } while ((nbytes = MYIO_read(dc_in, buf, sizeof(buf))) > 0) { apr_size_t len = nbytes; apr_file_write(astdout, buf, &len); MYIO_write(out, buf, nbytes); } } _FINALLY_: if (in) { MYIO_fp_close(in); in = NULL; } if (out) { MYIO_fp_close(out); out = NULL; } if (error_flag) { apr_file_printf(astderr, "failed.\n"); return 1; /* 異常終了 */ } apr_file_printf(astdout, "done.\n"); return 0; /* 正常終了 */ }