X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=src%2Fchxj_img_conv_format.c;h=a39d96a95d296aeceff76917a8eb0d4ecac08421;hb=2be9dc6fa88057738a788f1002b83e7b567a0b68;hp=3c757d8b29347b275072e402508782bb643c5f78;hpb=251f3229a9ac46edae400e0f45f5ea378de28888;p=modchxj%2Fmod_chxj.git diff --git a/src/chxj_img_conv_format.c b/src/chxj_img_conv_format.c index 3c757d8b..a39d96a9 100644 --- a/src/chxj_img_conv_format.c +++ b/src/chxj_img_conv_format.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2008 Atsushi Konno All rights reserved. + * Copyright (C) 2005-2009 Atsushi Konno All rights reserved. * Copyright (C) 2005 QSDN,Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,20 +24,25 @@ #include "chxj_apply_convrule.h" #include "chxj_url_encode.h" #include "qs_parse_string.h" +#include "chxj_preg_replace.h" #include "http_core.h" #include +#if !defined(LONG_LONG_MAX) && defined(LLONG_MAX) +# define LONG_LONG_MAX LLONG_MAX +#endif + #define EXIT_MAGICK_ERROR() \ do { \ char *description; ExceptionType severity; \ description=MagickGetException(magick_wand,&severity); \ - ap_log_rerror(APLOG_MARK,APLOG_DEBUG, 0, r,"%s %s %d %s\n",__FILE__,(__func__),__LINE__,description); \ + ap_log_rerror(APLOG_MARK,APLOG_ERR, 0, r,"%s %s %d %s\n",__FILE__,(__func__),__LINE__,description); \ description=(char *) MagickRelinquishMemory(description); \ DestroyMagickWand(magick_wand); \ - }while(1) + } while(0) typedef enum img_conv_mode_t { IMG_CONV_MODE_NORMAL = 0, @@ -61,10 +66,10 @@ typedef struct query_string_param_t query_string_param_t; struct query_string_param_t { img_conv_mode_t mode; - char* user_agent; + char *user_agent; ua_use_flag_t ua_flag; - char* name; /* for EZGET */ + char *name; /* for EZGET */ long offset; /* for EZGET */ long count; /* for EZGET */ int width; @@ -76,6 +81,7 @@ struct query_string_param_t { /*----------------------------------------------------------------------------*/ static device_table v_ignore_spec = { NULL, + 0, "IGN", "IGN", CHXJ_SPEC_HTML, @@ -93,6 +99,7 @@ static device_table v_ignore_spec = { 96, 65536, NULL, + "Shift_JIS" }; /*----------------------------------------------------------------------------*/ @@ -136,14 +143,14 @@ static unsigned short AU_CRC_TBL[256] = { /*----------------------------------------------------------------------------*/ /* Download page for AU */ /*----------------------------------------------------------------------------*/ -static const char* HDML_FIRST_PAGE = +static const char *HDML_FIRST_PAGE = "\r\n" " \r\n" " \r\n" " \r\n" "\r\n"; -static const char* HDML_SUCCESS_PAGE = +static const char *HDML_SUCCESS_PAGE = "\r\n" " \r\n" " \r\n" @@ -151,7 +158,7 @@ static const char* HDML_SUCCESS_PAGE = " \r\n" "\r\n"; -static const char* HDML_FAIL_PAGE = +static const char *HDML_FAIL_PAGE = "\r\n" " \r\n" " \r\n" @@ -159,101 +166,115 @@ static const char* HDML_FAIL_PAGE = " \r\n" "\r\n"; +static ap_regex_t *v_docomo_serial_pattern1 = NULL; +static ap_regex_t *v_docomo_serial_pattern2 = NULL; +static ap_regex_t *v_docomo_serial_pattern3 = NULL; +static ap_regex_t *v_softbank_serial_pattern1 = NULL; + /*----------------------------------------------------------------------------*/ /* Prototype declaration */ /*----------------------------------------------------------------------------*/ -static char* s_create_workfile( request_rec*, - mod_chxj_config* , - const char*, - query_string_param_t*); - -static apr_status_t s_create_cache_file(request_rec* r, - const char* tmpfile, - device_table* spec, - apr_finfo_t* st, - query_string_param_t* qsp, - mod_chxj_config *conf); - -static apr_status_t s_send_cache_file( device_table* spec, - query_string_param_t* query_string, - request_rec* r, - const char* tmpfile); - -static apr_status_t s_send_original_file(request_rec* r, - const char* originalfile); - -static apr_status_t s_header_only_cache_file(device_table* spec, - query_string_param_t* query_string, - request_rec* r, - const char* tmpfile); - -static query_string_param_t* s_get_query_string_param(request_rec *r); - -static unsigned short s_add_crc( const char* writedata, - apr_size_t witebyte); - -static MagickWand* s_fixup_size(MagickWand* , - request_rec* r, - device_table* spec, +static char *s_create_workfile_name(request_rec *, + mod_chxj_config *, + const char *, + query_string_param_t *); + +static apr_status_t s_create_cache_file(request_rec *r, + const char *tmpfile, + device_table *spec, + apr_finfo_t *st, + query_string_param_t *qsp, + mod_chxj_config *conf); + +static apr_status_t s_send_cache_file(mod_chxj_config *conf, + device_table *spec, + query_string_param_t *query_string, + request_rec *r, + const char *tmpfile); + +static apr_status_t s_send_original_file(request_rec *r, + const char *originalfile); + +static apr_status_t s_header_only_cache_file(device_table *spec, + query_string_param_t *query_string, + request_rec *r, + const char *tmpfile); + +static query_string_param_t *s_get_query_string_param(request_rec *r); + +static unsigned short s_add_crc(const char *writedata, apr_size_t witebyte); + +static MagickWand *s_fixup_size(MagickWand *, + request_rec *r, + device_table *spec, query_string_param_t *qsp); -static MagickWand* s_fixup_color(MagickWand* magick_wand, - request_rec* r, - device_table* spec, +static MagickWand *s_fixup_color(MagickWand *magick_wand, + request_rec *r, + device_table *spec, img_conv_mode_t mode); -static MagickWand* s_fixup_depth(MagickWand* magick_wand, +static MagickWand *s_fixup_depth(MagickWand* magick_wand, request_rec* r, device_table* spec); -static MagickWand* s_img_down_sizing(MagickWand* magick_wand, - request_rec* r, device_table* spec); +static MagickWand *s_img_down_sizing(MagickWand *magick_wand, + request_rec *r, device_table *spec); -static MagickWand* s_add_copyright(MagickWand* magick_wand, - request_rec* r, - device_table* spec); +static MagickWand *s_add_copyright(MagickWand *magick_wand, + request_rec *r, + device_table *spec); -static char* s_create_blob_data(request_rec* r, - device_table* spec, - query_string_param_t* qsp, - char* indata, - apr_size_t* len); +static char *s_create_blob_data(request_rec *r, + device_table *spec, + query_string_param_t *qsp, + char *indata, + apr_size_t *len); -static int s_img_conv_format_from_file(request_rec* r, - mod_chxj_config* conf, - const char* user_agent, - query_string_param_t* qsp, - device_table* spec); +static int s_img_conv_format_from_file(request_rec *r, + mod_chxj_config *conf, + const char *user_agent, + query_string_param_t *qsp, + device_table *spec); +static int s_convert_to_jpeg(MagickWand *magick_wand, request_rec *r, device_table *spec); +static int s_convert_to_png(MagickWand *maigck_wand, request_rec *r, device_table *spec); +static int s_convert_to_gif(MagickWand *magick_wand, request_rec *r, device_table *spec); +static int s_convert_to_bmp(MagickWand *magick_wand, request_rec *r, device_table *spec); +static int s_chxj_trans_name2(request_rec *r); +static char *s_add_comment_to_png(request_rec *r, char *data, apr_size_t *len); int -chxj_img_conv_format_handler(request_rec* r) +chxj_img_conv_format_handler(request_rec *r) { - mod_chxj_config* conf; - query_string_param_t* qsp; - char* user_agent; - device_table* spec; - chxjconvrule_entry* entryp; - - DBG(r, "start chxj_img_conv_format_handler()"); - - if ((*r->handler != 'c' && *r->handler != 'C') - || (strcasecmp(r->handler, "chxj-picture") - && strcasecmp(r->handler, "chxj-qrcode"))) { - DBG(r, "end chxj_img_conv_format_handler()"); + mod_chxj_config *conf; + query_string_param_t *qsp; + char *user_agent; + device_table *spec; + chxjconvrule_entry *entryp; + int rtn; + + DBG(r, "REQ[%X] start chxj_img_conv_format_handler()", (unsigned int)(apr_size_t)r); + + s_chxj_trans_name2(r); + + if (! r->handler || + (r->handler && !STRCASEEQ('c','C',"chxj-picture",r->handler) && !STRCASEEQ('c','C',"chxj-qrcode",r->handler))) { + DBG(r, "REQ[%X] Response Code:[%d]", (unsigned int)(apr_size_t)r, r->status); + DBG(r, "REQ[%X] end chxj_img_conv_format_handler() r->handler is[%s]", TO_ADDR(r), r->handler); return DECLINED; } qsp = s_get_query_string_param(r); - conf = ap_get_module_config(r->per_dir_config, &chxj_module); + conf = chxj_get_module_config(r->per_dir_config, &chxj_module); if (conf == NULL) { - DBG(r, "end chxj_img_conv_format_handler() conf is null"); + DBG(r, "REQ[%X] end chxj_img_conv_format_handler() conf is null",TO_ADDR(r)); return DECLINED; } - if (strcasecmp(r->handler, "chxj-qrcode") == 0 && conf->image == CHXJ_IMG_OFF) { + if (STRCASEEQ('c','C',"chxj-qrcode",r->handler) && conf->image == CHXJ_IMG_OFF) { + DBG(r, "REQ[%X] end chxj_img_conv_format_handler() chxj-qrcode and ImageEngineOff", (unsigned int)(apr_size_t)r); return DECLINED; } - /*------------------------------------------------------------------------*/ /* get UserAgent from http header */ /*------------------------------------------------------------------------*/ @@ -280,11 +301,13 @@ chxj_img_conv_format_handler(request_rec* r) else spec = chxj_specified_device(r, user_agent); - DBG(r,"found device_name=[%s]", spec->device_name); - DBG(r,"User-Agent=[%s]", user_agent); + DBG(r,"REQ[%X] found device_name=[%s]", (unsigned int)(apr_size_t)r, spec->device_name); + DBG(r,"REQ[%X] User-Agent=[%s]", (unsigned int)(apr_size_t)r, user_agent); - return s_img_conv_format_from_file(r, conf, user_agent, qsp, spec); + rtn = s_img_conv_format_from_file(r, conf, user_agent, qsp, spec); + DBG(r, "REQ[%X] end chxj_img_conv_format_handler()", (unsigned int)(apr_size_t)r); + return rtn; } @@ -296,30 +319,30 @@ chxj_img_conv_format_handler(request_rec* r) * @param src [i] It is former image binary data. * @param len [i/o] It is length of former image binary data. */ -char* -chxj_exchange_image(request_rec *r, const char** src, apr_size_t* len) +char * +chxj_convert_image(request_rec *r, const char **src, apr_size_t *len) { - mod_chxj_config* conf; - query_string_param_t* qsp; - char* user_agent; - device_table* spec; - char* dst; - char* conv_check; - chxjconvrule_entry* entryp; + mod_chxj_config *conf; + query_string_param_t *qsp; + char *user_agent; + device_table *spec; + char *dst; + char *conv_check; + chxjconvrule_entry *entryp; - DBG(r, "start chxj_exchange_image()"); + DBG(r, "REQ[%X] start chxj_convert_image()",(unsigned int)(apr_size_t)r); conv_check = (char*)apr_table_get(r->headers_in, "CHXJ_IMG_CONV"); if (conv_check) { - DBG(r, "end chxj_exchnage_image() already convert."); + DBG(r, "REQ[%X] end chxj_convert_image() already convert.", (unsigned int)(apr_size_t)r); return NULL; } qsp = s_get_query_string_param(r); - conf = ap_get_module_config(r->per_dir_config, &chxj_module); + conf = chxj_get_module_config(r->per_dir_config, &chxj_module); if (conf == NULL) { - DBG(r, "end chxj_exchange_image()"); + DBG(r, "REQ[%X] end chxj_convert_image()", (unsigned int)(apr_size_t)r); return NULL; } @@ -347,30 +370,33 @@ chxj_exchange_image(request_rec *r, const char** src, apr_size_t* len) DBG(r,"found device_name=[%s]", spec->device_name); DBG(r, "User-Agent=[%s]", user_agent); - if (spec->width == 0 || spec->heigh == 0) + if (spec->width == 0 || spec->heigh == 0) { + DBG(r, "REQ[%X] end chxj_convert_image() not convert (width or height is 0)", (unsigned int)(apr_size_t)r); return NULL; + } dst = s_create_blob_data(r, spec, qsp, (char*)*src, len); if (dst == NULL) *len = 0; - DBG(r, "end chxj_exchange_image()"); + DBG(r, "REQ[%X] end chxj_convert_image()", (unsigned int)(apr_size_t)r); return dst; } + static int s_img_conv_format_from_file( - request_rec* r, - mod_chxj_config* conf, - const char* user_agent, - query_string_param_t* qsp, - device_table* spec) + request_rec *r, + mod_chxj_config *conf, + const char *user_agent, + query_string_param_t *qsp, + device_table *spec) { apr_status_t rv; apr_finfo_t st; apr_finfo_t cache_st; - char* tmpfile; + char *tmpfile; int try_count; if (spec->html_spec_type == CHXJ_SPEC_UNKNOWN) { @@ -383,13 +409,14 @@ s_img_conv_format_from_file( /*--------------------------------------------------------------------------*/ /* Create Workfile Name */ /*--------------------------------------------------------------------------*/ - tmpfile = s_create_workfile(r, conf, user_agent, qsp); - DBG(r,"workfile=[%s]", tmpfile); + tmpfile = s_create_workfile_name(r, conf, user_agent, qsp); + DBG(r,"REQ[%X] workfile=[%s]", TO_ADDR(r), tmpfile); rv = apr_stat(&st, r->filename, APR_FINFO_MIN, r->pool); if (rv != APR_SUCCESS) return HTTP_NOT_FOUND; + apr_table_setn(r->headers_in, "CHXJ_IMG_CONV", "done"); try_count = CACHE_RETRY_COUNT; do { rv = apr_stat(&cache_st, tmpfile, APR_FINFO_MIN, r->pool); @@ -404,9 +431,9 @@ s_img_conv_format_from_file( return rv; } - DBG(r,"color=[%d]", spec->color); + DBG(r,"REQ[%X] color=[%d]", TO_ADDR(r), spec->color); if (! r->header_only) { - rv = s_send_cache_file(spec, qsp,r, tmpfile); + rv = s_send_cache_file(conf, spec, qsp,r, tmpfile); } else { rv = s_header_only_cache_file(spec, qsp, r, tmpfile); @@ -421,7 +448,6 @@ s_img_conv_format_from_file( WRN(r, "cache retry failure...."); WRN(r, "cache file was deleted..."); } - apr_table_setn(r->headers_in, "CHXJ_IMG_CONV", "done"); DBG(r,"end chxj_img_conv_format"); @@ -430,10 +456,10 @@ s_img_conv_format_from_file( static apr_status_t -s_create_cache_file(request_rec* r, - const char* tmpfile, - device_table* spec, - apr_finfo_t* st, +s_create_cache_file(request_rec *r, + const char *tmpfile, + device_table *spec, + apr_finfo_t *st, query_string_param_t *qsp, mod_chxj_config *conf) { @@ -443,22 +469,22 @@ s_create_cache_file(request_rec* r, unsigned short crc; img_conv_mode_t mode = qsp->mode; - char* writedata = NULL; - char* readdata = NULL; + char *writedata = NULL; + char *readdata = NULL; - apr_file_t* fout; - apr_file_t* fin; - apr_finfo_t cache_dir_st; + apr_file_t *fout; + apr_file_t *fin; + apr_finfo_t cache_dir_st; - MagickWand* magick_wand; + MagickWand *magick_wand; + int img_count; - if ((*r->handler == 'c' || *r->handler == 'C') - && strcasecmp(r->handler, "chxj-qrcode") == 0) { + if (STRCASEEQ('c','C',"chxj-qrcode",r->handler)) { /*------------------------------------------------------------------------*/ - /* QRCODEÍѤΥե¡¥¤¥ë¤Î¾ì¹ç */ + /* QRCODE用のファイルの場合 */ /*------------------------------------------------------------------------*/ Doc doc; - Node* root; + Node *root; qr_code_t qrcode; int sts; @@ -485,11 +511,11 @@ s_create_cache_file(request_rec* r, } else { /*------------------------------------------------------------------------*/ - /* Ä̾ï¤Î¥¤¥á¡¼¥¸¥Õ¥¡¥¤¥ë¤Î¾ì¹ç */ + /* 通常のイメージファイルの場合 */ /*------------------------------------------------------------------------*/ rv = apr_file_open(&fin, r->filename, - APR_READ|APR_BINARY , + APR_FOPEN_READ | APR_FOPEN_BINARY | APR_FOPEN_BUFFERED | APR_FOPEN_SHARELOCK | APR_FOPEN_SENDFILE_ENABLED, APR_OS_DEFAULT, r->pool); if (rv != APR_SUCCESS) { @@ -500,13 +526,13 @@ s_create_cache_file(request_rec* r, readdata = apr_palloc(r->pool, st->size); rv = apr_file_read_full(fin, (void*)readdata, st->size, &readbyte); if (rv != APR_SUCCESS || readbyte != st->size) { - DBG(r,"file read failed.[%s]", r->filename); + DBG(r,"REQ[%X] file read failed.[%s]", TO_ADDR(r), r->filename); apr_file_close(fin); return HTTP_NOT_FOUND; } } - DBG(r,"start img convert"); + DBG(r,"REQ[%X] start img convert", TO_ADDR(r)); magick_wand = NewMagickWand(); @@ -515,19 +541,53 @@ s_create_cache_file(request_rec* r, return HTTP_NOT_FOUND; } - if (spec->html_spec_type != CHXJ_SPEC_UNKNOWN) { - /* - * The size of the image is changed. - */ - DBG(r,"call s_fixup_size()"); - - if ((magick_wand = s_fixup_size(magick_wand, r, spec, qsp)) == NULL) + /*------------------*/ + /* for AnimationGIF */ + /*------------------*/ + img_count = MagickGetNumberImages(magick_wand); + DBG(r, "REQ[%X] img_count is [%d]", (unsigned int)(apr_size_t)r, img_count); + if (img_count > 1) { + MagickSetImageIndex(magick_wand, 0); + MagickWand *magick_wand2 = MagickGetImage(magick_wand); + DestroyMagickWand(magick_wand); + magick_wand = magick_wand2; + } + + if (MagickStripImage(magick_wand) == MagickFalse) { + ERR(r, "mod_chxj: strip image failure."); + EXIT_MAGICK_ERROR(); + return HTTP_NOT_FOUND; + } + { + MagickWand *magick_wand2; + if ((magick_wand2 = MagickCoalesceImages(magick_wand)) == NULL) { + EXIT_MAGICK_ERROR(); return HTTP_NOT_FOUND; + } + DestroyMagickWand(magick_wand); + magick_wand = magick_wand2; + } + + if (spec->html_spec_type != CHXJ_SPEC_UNKNOWN) { + int oldw = MagickGetImageWidth(magick_wand); + int oldh = MagickGetImageHeight(magick_wand); + int done_fixup_size = 0; + if ((qsp->mode == IMG_CONV_MODE_WALLPAPER && spec->wp_width < oldw && spec->wp_heigh < oldh) + || (qsp->mode != IMG_CONV_MODE_WALLPAPER && spec->width < oldw && spec->heigh < oldh)) { + /* + * The size of the image is changed. + */ + DBG(r,"REQ[%X] call s_fixup_size()", TO_ADDR(r)); + if ((magick_wand = s_fixup_size(magick_wand, r, spec, qsp)) == NULL) + return HTTP_NOT_FOUND; + + done_fixup_size = 1; + } /* * The colors of the image is changed. */ - DBG(r,"call s_fixup_color()"); + DBG(r,"REQ[%X] call s_fixup_color()", TO_ADDR(r)); if ((magick_wand = s_fixup_color(magick_wand, r,spec, mode)) == NULL) return HTTP_NOT_FOUND; @@ -535,110 +595,83 @@ s_create_cache_file(request_rec* r, /* * DEPTH of the image is changed. */ - DBG(r,"call s_fixup_depth()"); + DBG(r,"REQ[%X] call s_fixup_depth()", TO_ADDR(r)); if ((magick_wand = s_fixup_depth(magick_wand, r, spec)) == NULL) return HTTP_NOT_FOUND; - - DBG(r,"start convert and compression"); - - if (spec->available_jpeg) { - if (MagickSetImageCompression(magick_wand,JPEGCompression) == MagickFalse) { - EXIT_MAGICK_ERROR(); - return HTTP_NOT_FOUND; - } - - if (MagickSetImageFormat(magick_wand, "jpg") == MagickFalse) { - EXIT_MAGICK_ERROR(); - return HTTP_NOT_FOUND; - } - - if (MagickStripImage(magick_wand) == MagickFalse) { - EXIT_MAGICK_ERROR(); - return HTTP_NOT_FOUND; - } - - if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL) + if (! done_fixup_size) { + /* + * The size of the image is changed. + */ + DBG(r,"REQ[%X] call s_fixup_size()", TO_ADDR(r)); + if ((magick_wand = s_fixup_size(magick_wand, r, spec, qsp)) == NULL) return HTTP_NOT_FOUND; - - r->content_type = apr_psprintf(r->pool, "image/jpeg"); - DBG(r,"convert to jpg"); } - else - if (spec->available_png) { - - if (MagickSetImageCompression(magick_wand,ZipCompression) == MagickFalse) { - EXIT_MAGICK_ERROR(); - return HTTP_NOT_FOUND; - } - - if (MagickSetImageFormat(magick_wand, "png") == MagickFalse) { - EXIT_MAGICK_ERROR(); - return HTTP_NOT_FOUND; - } - - if (MagickStripImage(magick_wand) == MagickFalse) { - EXIT_MAGICK_ERROR(); - return HTTP_NOT_FOUND; + + char *nowFormat = MagickGetImageFormat(magick_wand); + int fixFormatFlag = 0; + if (nowFormat) { + if (STRCASEEQ('g','G',"gif",nowFormat)) { + if (spec->available_gif) { + if (s_convert_to_gif(magick_wand, r, spec)) { + return HTTP_NOT_FOUND; + } + fixFormatFlag = 1; + } } - - if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL) - return HTTP_NOT_FOUND; - - r->content_type = apr_psprintf(r->pool, "image/png"); - DBG(r, "convert to png"); - } - else - if (spec->available_gif) { - - if (MagickSetImageCompression(magick_wand,LZWCompression) == MagickFalse) { - EXIT_MAGICK_ERROR(); - return HTTP_NOT_FOUND; + else if (STRCASEEQ('j','J',"jpg",nowFormat)||STRCASEEQ('j','J',"jpeg",nowFormat)) { + if (spec->available_jpeg) { + if (s_convert_to_jpeg(magick_wand, r, spec)) { + return HTTP_NOT_FOUND; + } + fixFormatFlag = 1; + } } - - if (MagickSetImageFormat(magick_wand, "gif") == MagickFalse) { - EXIT_MAGICK_ERROR(); - return HTTP_NOT_FOUND; + else if (STRCASEEQ('p','P',"png",nowFormat)) { + if (spec->available_png) { + if (s_convert_to_png(magick_wand, r, spec)) { + return HTTP_NOT_FOUND; + } + fixFormatFlag = 1; + } } - - if (MagickStripImage(magick_wand) == MagickFalse) { - EXIT_MAGICK_ERROR(); - return HTTP_NOT_FOUND; + else if (STRCASEEQ('b','B',"bmp",nowFormat)) { + if (spec->available_bmp4 || spec->available_bmp2) { + if (s_convert_to_bmp(magick_wand, r, spec)) { + return HTTP_NOT_FOUND; + } + fixFormatFlag = 1; + } } - - if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL) - return HTTP_NOT_FOUND; - - r->content_type = apr_psprintf(r->pool, "image/gif"); - - DBG(r,"convert to gif"); } - else - if (spec->available_bmp2 || spec->available_bmp4) { + + DBG(r,"REQ[%X] start convert and compression", TO_ADDR(r)); - if (MagickSetImageCompression(magick_wand,NoCompression) == MagickFalse) { - EXIT_MAGICK_ERROR(); - return HTTP_NOT_FOUND; + if (! fixFormatFlag) { + if (spec->available_jpeg) { + if (s_convert_to_jpeg(magick_wand, r, spec)) { + return HTTP_NOT_FOUND; + } } - - if (MagickSetImageFormat(magick_wand, "bmp") == MagickFalse) { - EXIT_MAGICK_ERROR(); - return HTTP_NOT_FOUND; + else if (spec->available_gif) { + if (s_convert_to_gif(magick_wand, r, spec)) { + return HTTP_NOT_FOUND; + } } + else if (spec->available_png) { + if (s_convert_to_png(magick_wand, r, spec)) { + return HTTP_NOT_FOUND; + } - if (MagickStripImage(magick_wand) == MagickFalse) { - EXIT_MAGICK_ERROR(); - return HTTP_NOT_FOUND; } - - if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL) - return HTTP_NOT_FOUND; - - r->content_type = apr_psprintf(r->pool, "image/bmp"); - - DBG(r, "convert to bmp(unsupported)"); + else + if (spec->available_bmp2 || spec->available_bmp4) { + if (s_convert_to_bmp(magick_wand, r, spec)) { + return HTTP_NOT_FOUND; + } + } } /* @@ -679,7 +712,8 @@ s_create_cache_file(request_rec* r, } } - writedata = (char*)MagickGetImageBlob(magick_wand, &writebyte); + char *sv_writedata; + sv_writedata = writedata = (char*)MagickGetImageBlob(magick_wand, &writebyte); if (! writebyte) { DestroyMagickWand(magick_wand); @@ -687,14 +721,27 @@ s_create_cache_file(request_rec* r, return HTTP_INTERNAL_SERVER_ERROR; } + writedata = apr_palloc(r->pool, writebyte); + memcpy(writedata, sv_writedata, writebyte); DBG(r, "end convert and compression"); + + /* Added PNG Comment if type is image/png. */ + if (r->content_type && strcmp(r->content_type, "image/png") == 0) { + if ((writedata = s_add_comment_to_png(r, writedata, &writebyte)) == NULL) { + DBG(r, "REQ[%X] Add comment to PNG failure.",(unsigned int)(apr_size_t)r); + DestroyMagickWand(magick_wand); + if (sv_writedata) free(sv_writedata); + return HTTP_INTERNAL_SERVER_ERROR; + } + } /* check limit */ rv = apr_stat(&cache_dir_st, conf->image_cache_dir, APR_FINFO_MIN, r->pool); if (rv != APR_SUCCESS) { DestroyMagickWand(magick_wand); ERR(r,"dir stat error.[%s]", conf->image_cache_dir); + if (sv_writedata) free(sv_writedata); return HTTP_INTERNAL_SERVER_ERROR; } @@ -712,6 +759,7 @@ s_create_cache_file(request_rec* r, if (rv != APR_SUCCESS) { DestroyMagickWand(magick_wand); ERR(r,"dir open error.[%s]", conf->image_cache_dir); + if (sv_writedata) free(sv_writedata); return HTTP_INTERNAL_SERVER_ERROR; } memset(&dcf, 0, sizeof(apr_finfo_t)); @@ -742,15 +790,17 @@ s_create_cache_file(request_rec* r, ERR(r, "At least the same size as %luByte is necessary for me.", (unsigned long)writebyte); ERR(r, "Please specify the ChxjImageCacheLimit that is larger than now value. "); ERR(r, "=========================================="); + if (sv_writedata) free(sv_writedata); return HTTP_INTERNAL_SERVER_ERROR; } DBG(r, "Image Cache dir is full. total_size:[%lu] max_size:[%lu]", total_size + writebyte, max_size); /* search delete candidate */ delete_file_name = apr_psprintf(r->pool, "%s/%s", conf->image_cache_dir, dcf.name); - DBG(r, "delete image cache target:[%s] atime:[%lld]", delete_file_name, dcf.atime); + DBG(r, "delete image cache target:[%s] atime:[%lld]", delete_file_name, (long long int)dcf.atime); rv = apr_file_remove(delete_file_name, r->pool); if (rv != APR_SUCCESS) { ERR(r, "cache file delete failure.[%s]", delete_file_name); + if (sv_writedata) free(sv_writedata); return HTTP_INTERNAL_SERVER_ERROR; } DBG(r, "deleted image cache target:[%s]", delete_file_name); @@ -762,11 +812,13 @@ s_create_cache_file(request_rec* r, /* to cache */ rv = apr_file_open(&fout, tmpfile, - APR_WRITE| APR_CREATE | APR_BINARY | APR_SHARELOCK ,APR_OS_DEFAULT, + APR_FOPEN_WRITE| APR_FOPEN_CREATE | APR_FOPEN_BINARY | APR_SHARELOCK , + APR_OS_DEFAULT, r->pool); if (rv != APR_SUCCESS) { DestroyMagickWand(magick_wand); - ERR(r,"file open error.[%s]", tmpfile); + ERR(r,"REQ[%X] file open error.[%s]", TO_ADDR(r), tmpfile); + if (sv_writedata) free(sv_writedata); return HTTP_INTERNAL_SERVER_ERROR; } @@ -774,6 +826,7 @@ s_create_cache_file(request_rec* r, if (rv != APR_SUCCESS) { DestroyMagickWand(magick_wand); apr_file_close(fout); + if (sv_writedata) free(sv_writedata); return HTTP_INTERNAL_SERVER_ERROR; } @@ -788,17 +841,20 @@ s_create_cache_file(request_rec* r, rv = apr_file_putc((crc >> 8) & 0xff, fout); if (rv != APR_SUCCESS) { DestroyMagickWand(magick_wand); + if (sv_writedata) free(sv_writedata); return HTTP_INTERNAL_SERVER_ERROR; } rv = apr_file_putc( crc & 0xff, fout); if (rv != APR_SUCCESS) { DestroyMagickWand(magick_wand); + if (sv_writedata) free(sv_writedata); return HTTP_INTERNAL_SERVER_ERROR; } } DestroyMagickWand(magick_wand); + if (sv_writedata) free(sv_writedata); rv = apr_file_close(fout); if (rv != APR_SUCCESS) { @@ -810,153 +866,251 @@ s_create_cache_file(request_rec* r, } -static char* -s_create_blob_data(request_rec* r, - device_table* spec, - query_string_param_t *qsp, - char* indata, - apr_size_t* len) +static int +s_convert_to_jpeg(MagickWand *magick_wand, request_rec *r, device_table *spec) { - apr_size_t writebyte; - unsigned short crc; - img_conv_mode_t mode = qsp->mode; + if (MagickSetImageCompression(magick_wand,JPEGCompression) == MagickFalse) { + EXIT_MAGICK_ERROR(); + return -1; + } + + if (MagickSetImageFormat(magick_wand, "jpg") == MagickFalse) { + EXIT_MAGICK_ERROR(); + return -1; + } + + if (MagickStripImage(magick_wand) == MagickFalse) { + EXIT_MAGICK_ERROR(); + return -1; + } + + if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL) + return -1; + + r->content_type = apr_psprintf(r->pool, "image/jpeg"); + ap_set_content_type(r, "image/jpeg"); + DBG(r,"convert to jpg"); + return 0; +} - char* writedata = NULL; - char* dst = NULL; - MagickWand* magick_wand; +static int +s_convert_to_png(MagickWand *magick_wand, request_rec *r, device_table *spec) +{ + if (MagickSetImageCompression(magick_wand,ZipCompression) == MagickFalse) { + EXIT_MAGICK_ERROR(); + return -1; + } + + if (MagickSetImageFormat(magick_wand, "png") == MagickFalse) { + EXIT_MAGICK_ERROR(); + return -1; + } + + if (MagickStripImage(magick_wand) == MagickFalse) { + EXIT_MAGICK_ERROR(); + return -1; + } + + if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL) + return -1; + + r->content_type = apr_psprintf(r->pool, "image/png"); + ap_set_content_type(r, "image/png"); + DBG(r, "convert to png"); + return 0; +} - magick_wand = NewMagickWand(); - if (MagickReadImageBlob(magick_wand,indata, *len) == MagickFalse) { +static int +s_convert_to_gif(MagickWand *magick_wand, request_rec *r, device_table *spec) +{ + if (MagickSetImageCompression(magick_wand,LZWCompression) == MagickFalse) { EXIT_MAGICK_ERROR(); - return NULL; + return -1; } + + if (MagickSetImageFormat(magick_wand, "gif") == MagickFalse) { + EXIT_MAGICK_ERROR(); + return -1; + } + + if (MagickStripImage(magick_wand) == MagickFalse) { + EXIT_MAGICK_ERROR(); + return -1; + } + + if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL) + return -1; + + r->content_type = apr_psprintf(r->pool, "image/gif"); + ap_set_content_type(r, "image/gif"); + + DBG(r,"convert to gif"); + return 0; +} - /* - * The size of the image is changed. - */ - DBG(r, "call s_fixup_size()"); - if ((magick_wand = s_fixup_size(magick_wand, r, spec, qsp)) == NULL) - return NULL; +static int +s_convert_to_bmp(MagickWand *magick_wand, request_rec *r, device_table *spec) +{ + if (MagickSetImageCompression(magick_wand,NoCompression) == MagickFalse) { + EXIT_MAGICK_ERROR(); + return -1; + } + + if (MagickSetImageFormat(magick_wand, "bmp") == MagickFalse) { + EXIT_MAGICK_ERROR(); + return -1; + } + + if (MagickStripImage(magick_wand) == MagickFalse) { + EXIT_MAGICK_ERROR(); + return -1; + } + + if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL) + return -1; + + r->content_type = apr_psprintf(r->pool, "image/bmp"); + ap_set_content_type(r, "image/bmp"); + + DBG(r, "convert to bmp(unsupported)"); + return 0; +} - /* - * The colors of the image is changed. - */ - DBG(r, "call s_fixup_color()"); - if ((magick_wand = s_fixup_color(magick_wand, r,spec, mode)) == NULL) - return NULL; +static char * +s_create_blob_data(request_rec *r, + device_table *spec, + query_string_param_t *qsp, + char *indata, + apr_size_t *len) +{ + apr_size_t writebyte; + unsigned short crc; + img_conv_mode_t mode = qsp->mode; - /* - * DEPTH of the image is changed. - */ + char *writedata = NULL; + char *dst = NULL; + MagickWand *magick_wand; - DBG(r,"call s_fixup_depth()"); + magick_wand = NewMagickWand(); - if ((magick_wand = s_fixup_depth(magick_wand, r, spec)) == NULL) + if (MagickReadImageBlob(magick_wand,indata, *len) == MagickFalse) { + EXIT_MAGICK_ERROR(); return NULL; + } + if (MagickStripImage(magick_wand) == MagickFalse) { + ERR(r, "mod_chxj: strip image failure."); + EXIT_MAGICK_ERROR(); + return NULL; + } + { + int oldw = MagickGetImageWidth(magick_wand); + int oldh = MagickGetImageHeight(magick_wand); + int done_fixup_size = 0; + if ((qsp->mode == IMG_CONV_MODE_WALLPAPER && spec->wp_width < oldw && spec->wp_heigh < oldh) + || (qsp->mode != IMG_CONV_MODE_WALLPAPER && spec->width < oldw && spec->heigh < oldh)) { + /* + * The size of the image is changed. + */ + DBG(r,"call s_fixup_size()"); - DBG(r,"start convert and compression"); - - if (spec->available_jpeg) { - if (MagickSetImageCompression(magick_wand,JPEGCompression) == MagickFalse) { - EXIT_MAGICK_ERROR(); - return NULL; - } + if ((magick_wand = s_fixup_size(magick_wand, r, spec, qsp)) == NULL) { + EXIT_MAGICK_ERROR(); + return NULL; + } - if (MagickSetImageFormat(magick_wand, "jpg") == MagickFalse) { - EXIT_MAGICK_ERROR(); - return NULL; + done_fixup_size = 1; } + /* + * The colors of the image is changed. + */ + DBG(r,"call s_fixup_color()"); - if (MagickStripImage(magick_wand) == MagickFalse) { + if ((magick_wand = s_fixup_color(magick_wand, r,spec, mode)) == NULL) { EXIT_MAGICK_ERROR(); return NULL; } - if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL) - return NULL; - - r->content_type = apr_psprintf(r->pool, "image/jpeg"); + /* + * DEPTH of the image is changed. + */ + DBG(r,"call s_fixup_depth()"); - DBG(r, "convert to jpg"); - } - else - if (spec->available_png) { - if (MagickSetImageCompression(magick_wand,ZipCompression) == MagickFalse) { + if ((magick_wand = s_fixup_depth(magick_wand, r, spec)) == NULL) { EXIT_MAGICK_ERROR(); return NULL; } - if (MagickSetImageFormat(magick_wand, "png") == MagickFalse) { - EXIT_MAGICK_ERROR(); - return NULL; - } - if (MagickStripImage(magick_wand) == MagickFalse) { - EXIT_MAGICK_ERROR(); - return NULL; + if (! done_fixup_size) { + /* + * The size of the image is changed. + */ + DBG(r,"call s_fixup_size()"); + if ((magick_wand = s_fixup_size(magick_wand, r, spec, qsp)) == NULL) { + EXIT_MAGICK_ERROR(); + return NULL; + } } - - if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL) - return NULL; - - r->content_type = apr_psprintf(r->pool, "image/png"); - - DBG(r,"convert to png"); } - else - if (spec->available_gif) { - if (MagickSetImageCompression(magick_wand,LZWCompression) == MagickFalse) { - EXIT_MAGICK_ERROR(); - return NULL; + char *nowFormat = MagickGetImageFormat(magick_wand); + int fixFormatFlag = 0; + if (nowFormat) { + if (STRCASEEQ('g','G',"gif",nowFormat)) { + if (spec->available_gif) { + if (s_convert_to_gif(magick_wand, r, spec)) { + return NULL; + } + fixFormatFlag = 1; + } } - - if (MagickSetImageFormat(magick_wand, "gif") == MagickFalse) { - EXIT_MAGICK_ERROR(); - return NULL; + else if (STRCASEEQ('j','J',"jpg",nowFormat)||STRCASEEQ('j','J',"jpeg",nowFormat)) { + if (spec->available_jpeg) { + if (s_convert_to_jpeg(magick_wand, r, spec)) { + return NULL; + } + fixFormatFlag = 1; + } } - - if (MagickStripImage(magick_wand) == MagickFalse) { - EXIT_MAGICK_ERROR(); - return NULL; + else if (STRCASEEQ('p','P',"png",nowFormat)) { + if (spec->available_png) { + if (s_convert_to_png(magick_wand, r, spec)) { + return NULL; + } + fixFormatFlag = 1; + } } + } - if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL) - return NULL; - - r->content_type = apr_psprintf(r->pool, "image/gif"); + DBG(r,"start convert and compression"); - DBG(r,"convert to gif"); - } - else - if (spec->available_bmp2 || spec->available_bmp4) { - if (MagickSetImageCompression(magick_wand,NoCompression) == MagickFalse) { - EXIT_MAGICK_ERROR(); - return NULL; + if (!fixFormatFlag) { + if (spec->available_jpeg) { + if (s_convert_to_jpeg(magick_wand, r, spec)) { + return NULL; + } } - - if (MagickSetImageFormat(magick_wand, "bmp") == MagickFalse) { - EXIT_MAGICK_ERROR(); - return NULL; + else if (spec->available_png) { + if (s_convert_to_png(magick_wand, r, spec)) { + return NULL; + } } - - if (MagickStripImage(magick_wand) == MagickFalse) { - EXIT_MAGICK_ERROR(); - return NULL; + else if (spec->available_gif) { + if (s_convert_to_gif(magick_wand, r, spec)) { + return NULL; + } + } + else if (spec->available_bmp2 || spec->available_bmp4) { + if (s_convert_to_bmp(magick_wand, r, spec)) { + return NULL; + } } - - if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL) - return NULL; - - r->content_type = apr_psprintf(r->pool, "image/bmp"); - - DBG(r,"convert to bmp(unsupported)"); } /*--------------------------------------------------------------------------*/ /* Add Comment (Copyright and so on.) */ @@ -998,11 +1152,12 @@ s_create_blob_data(request_rec* r, return dst; } -static MagickWand* -s_fixup_size(MagickWand* magick_wand, - request_rec* r, - device_table* spec, - query_string_param_t *qsp) + +static MagickWand * +s_fixup_size(MagickWand *magick_wand, + request_rec *r, + device_table *spec, + query_string_param_t *qsp) { img_conv_mode_t mode = qsp->mode; int oldw; @@ -1081,6 +1236,9 @@ s_fixup_size(MagickWand* magick_wand, break; } + if (neww == 0) neww = 1; + if (newh == 0) newh = 1; + if (spec->html_spec_type != CHXJ_SPEC_UNKNOWN) { DBG(r,"convert width=[%d --> %d]", oldw, neww); DBG(r,"convert heigh=[%d --> %d]", oldh, newh); @@ -1148,8 +1306,9 @@ s_fixup_size(MagickWand* magick_wand, return magick_wand; } -static MagickWand* -s_fixup_color(MagickWand* magick_wand, request_rec* r, device_table* spec, img_conv_mode_t UNUSED(mode)) + +static MagickWand * +s_fixup_color(MagickWand *magick_wand, request_rec *r, device_table *spec, img_conv_mode_t UNUSED(mode)) { DBG(r,"start chxj_fixup_clor()"); @@ -1158,6 +1317,13 @@ s_fixup_color(MagickWand* magick_wand, request_rec* r, device_table* spec, img_c return magick_wand; } + unsigned long colors = MagickGetImageColors(magick_wand); + DBG(r, "now color:[%ld] spec->color:[%ld]", colors, (unsigned long)spec->color); + if (colors < (unsigned long)spec->color) { + DBG(r, "Pass s_fixup_color proc. color:[%ld] spec->color:[%d]", colors, spec->color); + return magick_wand; + } + if (spec->color >= 256) { DBG(r,"call MagickQuantizeImage() spec->color=[%d]",spec->color); @@ -1199,8 +1365,8 @@ s_fixup_color(MagickWand* magick_wand, request_rec* r, device_table* spec, img_c -static MagickWand* -s_fixup_depth(MagickWand* magick_wand, request_rec* r, device_table* spec) +static MagickWand * +s_fixup_depth(MagickWand *magick_wand, request_rec *r, device_table *spec) { if (spec->html_spec_type == CHXJ_SPEC_UNKNOWN) { DBG(r, "Pass s_fixup_depth proc"); @@ -1260,10 +1426,10 @@ s_fixup_depth(MagickWand* magick_wand, request_rec* r, device_table* spec) } -static MagickWand* -s_add_copyright(MagickWand* magick_wand, request_rec* r, device_table* spec) +static MagickWand * +s_add_copyright(MagickWand *magick_wand, request_rec *r, device_table *spec) { - mod_chxj_config* conf = ap_get_module_config(r->per_dir_config, &chxj_module); + mod_chxj_config *conf = chxj_get_module_config(r->per_dir_config, &chxj_module); if (spec->html_spec_type == CHXJ_SPEC_UNKNOWN) { DBG(r, "Pass add_copiright proc"); @@ -1274,7 +1440,8 @@ s_add_copyright(MagickWand* magick_wand, request_rec* r, device_table* spec) DBG(r, "Add COPYRIGHT [%s]", conf->image_copyright); - if (spec->html_spec_type == CHXJ_SPEC_Jhtml) { + if (spec->html_spec_type == CHXJ_SPEC_Jhtml + || spec->html_spec_type == CHXJ_SPEC_Jxhtml) { apr_table_setn(r->headers_out, "x-jphone-copyright", "no-transfer"); if (MagickCommentImage(magick_wand, apr_psprintf(r->pool, @@ -1310,56 +1477,69 @@ on_error: return NULL; } -static MagickWand* -s_img_down_sizing(MagickWand* magick_wand, request_rec* r, device_table* spec) +static MagickWand * +s_img_down_sizing(MagickWand *magick_wand, request_rec *r, device_table *spec) { MagickBooleanType status; - unsigned long quality = 70; - apr_size_t writebyte = 0; - char* writedata; - apr_size_t prev_size = 0; - int revers_flag = 0; - - writedata = (char*)MagickGetImageBlob(magick_wand, &writebyte); + unsigned long quality = 70; + apr_size_t writebyte = 0; + char *writedata; + apr_size_t prev_size = 0; + char *fmt; + int fmt_type = 0; + + writedata = (char *)MagickGetImageBlob(magick_wand, &writebyte); prev_size = writebyte; - do { - if (MagickSetImageCompressionQuality(magick_wand, quality) == MagickFalse) { - EXIT_MAGICK_ERROR(); - return NULL; - } - - writedata = (char*)MagickGetImageBlob(magick_wand, &writebyte); - if (writebyte >= prev_size || revers_flag) { - DBG(r, "quality=[%ld] size=[%d]", (long)quality, (int)writebyte); - revers_flag = 1; - quality += 10; - if (quality > 100) { - if (MagickSetImageCompression(magick_wand,NoCompression) == MagickFalse) { + + fmt = MagickGetImageFormat(magick_wand); + if (fmt) { + if (STRCASEEQ('j','J',"jpg",fmt)) fmt_type = 1; + if (STRCASEEQ('p','P',"png",fmt)) fmt_type = 2; + if (STRCASEEQ('g','G',"gif",fmt)) fmt_type = 3; + if (STRCASEEQ('b','B',"bmp",fmt)) fmt_type = 4; + } + if (fmt_type == 1) { + do { + if (MagickSetImageCompressionQuality(magick_wand, quality) == MagickFalse) { + EXIT_MAGICK_ERROR(); + return NULL; + } + + writedata = (char*)MagickGetImageBlob(magick_wand, &writebyte); + if (writebyte >= prev_size) { + DBG(r, "quality=[%ld] size=[%d]", (long)quality, (int)writebyte); + quality += 5; + if (quality > 100) { + if (MagickSetImageCompression(magick_wand,NoCompression) == MagickFalse) { + EXIT_MAGICK_ERROR(); + return NULL; + } + break; + } + if (MagickSetImageCompressionQuality(magick_wand, quality) == MagickFalse) { EXIT_MAGICK_ERROR(); return NULL; } break; } - prev_size = writebyte; - continue; + + DBG(r, "quality=[%ld] size=[%d]", (long)quality, (int)writebyte); + + if (spec->cache == 0) + break; + + if (writebyte <= (unsigned int)spec->cache) + break; + + quality -= 5; + + if (quality == 0 || quality > 100) + break; + } - - DBG(r, "quality=[%ld] size=[%d]", (long)quality, (int)writebyte); - - if (spec->cache == 0) - break; - - if (writebyte <= (unsigned int)spec->cache) - break; - - quality -= 10; - - if (quality == 0 || quality > 100) - break; - + while (1); } - while (1); if (spec->cache > 0 @@ -1384,6 +1564,7 @@ s_img_down_sizing(MagickWand* magick_wand, request_rec* r, device_table* spec) if (now_color <= 2) break; + if (now_color >= 8) { status = MagickQuantizeImage(magick_wand, now_color, @@ -1405,12 +1586,12 @@ s_img_down_sizing(MagickWand* magick_wand, request_rec* r, device_table* spec) EXIT_MAGICK_ERROR(); return NULL; } - - if (MagickSetImageDepth(magick_wand, depth) == MagickFalse) { - EXIT_MAGICK_ERROR(); - return NULL; + if (fmt_type != 2) { + if (MagickSetImageDepth(magick_wand, depth) == MagickFalse) { + EXIT_MAGICK_ERROR(); + return NULL; + } } - writedata = (char*)MagickGetImageBlob(magick_wand, &writebyte); DBG(r,"now_color=[%ld] size=[%d]", (long)now_color, (int)writebyte); @@ -1424,38 +1605,36 @@ s_img_down_sizing(MagickWand* magick_wand, request_rec* r, device_table* spec) return magick_wand; } + static apr_status_t -s_send_cache_file(device_table* spec, query_string_param_t* query_string, request_rec* r, const char* tmpfile) +s_send_cache_file( + mod_chxj_config *conf, + device_table *spec, + query_string_param_t *query_string, + request_rec *r, + const char *tmpfile) { apr_status_t rv; apr_finfo_t st; - apr_file_t* fout; + apr_file_t *fout; apr_size_t sendbyte; - char* contentLength; + char *contentLength; rv = apr_stat(&st, tmpfile, APR_FINFO_MIN, r->pool); if (rv != APR_SUCCESS) return HTTP_NOT_FOUND; - DBG(r, "mode:[%d]", query_string->mode); - DBG(r, "name:[%s]", query_string->name); - DBG(r, "offset:[%ld]", query_string->offset); - DBG(r, "count:[%ld]", query_string->count); + DBG(r, "REQ[%X] mode:[%d]", TO_ADDR(r), query_string->mode); + DBG(r, "REQ[%X] name:[%s]", TO_ADDR(r), query_string->name); + DBG(r, "REQ[%X] offset:[%ld]", TO_ADDR(r), query_string->offset); + DBG(r, "REQ[%X] count:[%ld]", TO_ADDR(r), query_string->count); - if (spec->available_jpeg) { - r->content_type = apr_psprintf(r->pool, "image/jpeg"); - } - else - if (spec->available_png) { - r->content_type = apr_psprintf(r->pool, "image/png"); - } - else - if (spec->available_gif) { - r->content_type = apr_psprintf(r->pool, "image/gif"); - } - else - if (spec->available_bmp2 || spec->available_bmp4) { - r->content_type = apr_psprintf(r->pool, "image/bmp"); + /* for mod_cache */ + { + apr_table_setn(r->headers_out, "Vary", "User-Agent"); + apr_table_setn(r->err_headers_out, "Vary", "User-Agent"); + ap_update_mtime(r, st.mtime); + ap_set_last_modified(r); } if (query_string->mode != IMG_CONV_MODE_EZGET && query_string->name == NULL) { @@ -1463,66 +1642,106 @@ s_send_cache_file(device_table* spec, query_string_param_t* query_string, reques apr_table_setn(r->headers_out, "Content-Length", (const char*)contentLength); DBG(r,"Content-Length:[%d]", (int)st.size); - + MagickWand *magick_wand = NewMagickWand(); + if (MagickReadImage(magick_wand,tmpfile) == MagickFalse) { + EXIT_MAGICK_ERROR(); + return HTTP_NOT_FOUND; + } + if (MagickStripImage(magick_wand) == MagickFalse) { + ERR(r, "mod_chxj: strip image failure."); + EXIT_MAGICK_ERROR(); + return HTTP_NOT_FOUND; + } + char *nowFormat = MagickGetImageFormat(magick_wand); + DestroyMagickWand(magick_wand); + if (nowFormat) { + if (STRCASEEQ('j','J',"jpeg",nowFormat) || STRCASEEQ('j','J',"jpg",nowFormat)) { + DBG(r, "detect cache file => jpg."); + ap_set_content_type(r, "image/jpeg"); + } + else if (STRCASEEQ('p','P',"png", nowFormat)) { + DBG(r, "detect cache file => png."); + ap_set_content_type(r, "image/png"); + } + else if (STRCASEEQ('g','G',"gif", nowFormat)) { + DBG(r, "detect cache file => gif."); + ap_set_content_type(r, "image/gif"); + } + else if (STRCASEEQ('b','B',"bmp", nowFormat)) { + DBG(r, "detect cache file => bmp."); + ap_set_content_type(r, "image/bmp"); + } + else { + ERR(r, "detect unknown file"); + return HTTP_NOT_FOUND; + } + } + if (conf->image_copyright) { + DBG(r, "REQ[%X] Add COPYRIGHT Header for SoftBank [%s]", TO_ADDR(r), conf->image_copyright); + if (spec->html_spec_type == CHXJ_SPEC_Jhtml || spec->html_spec_type == CHXJ_SPEC_Jxhtml) { + apr_table_setn(r->headers_out, "x-jphone-copyright", "no-transfer"); + } + } rv = apr_file_open(&fout, tmpfile, - APR_READ | APR_BINARY, APR_OS_DEFAULT, r->pool); + APR_FOPEN_READ | APR_FOPEN_BINARY | APR_FOPEN_BUFFERED | APR_FOPEN_SHARELOCK | APR_FOPEN_SENDFILE_ENABLED, + APR_OS_DEFAULT, r->pool); if (rv != APR_SUCCESS) { DBG(r, "cache file open failed[%s]", tmpfile); return HTTP_NOT_FOUND; } - ap_send_fd(fout, r, 0, st.size, &sendbyte); apr_file_close(fout); ap_rflush(r); - DBG(r, "send file data[%d]byte", (int)sendbyte); + DBG(r, "REQ[%X] send file data[%d]byte", TO_ADDR(r), (int)sendbyte); } else if (query_string->mode == IMG_CONV_MODE_EZGET) { - char* name = apr_pstrdup(r->pool, basename(r->filename)); + char *name = apr_pstrdup(r->pool, basename(r->filename)); name[strlen(name)-4] = 0; if (strcasecmp(r->content_type, "image/jpeg") == 0) { - ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS"); + chxj_set_content_type(r, "text/x-hdml; charset=Shift_JIS"); ap_rprintf(r, HDML_FIRST_PAGE, r->uri, name, ".jpg", (long)st.size, "devjaww", name); } else if (strcasecmp(r->content_type, "image/bmp") == 0) { - ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS"); + chxj_set_content_type(r, "text/x-hdml; charset=Shift_JIS"); ap_rprintf(r, HDML_FIRST_PAGE, r->uri, name, ".bmp", (long)st.size, "devabm", name); } else if (strcasecmp(r->content_type, "image/png") == 0) { - ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS"); + chxj_set_content_type(r, "text/x-hdml; charset=Shift_JIS"); ap_rprintf(r, HDML_FIRST_PAGE, r->uri, name, ".png", (long)st.size, "dev8aww", name); } else if (strcasecmp(r->content_type, "image/gif") == 0) { - ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS"); + chxj_set_content_type(r, "text/x-hdml; charset=Shift_JIS"); ap_rprintf(r, HDML_FIRST_PAGE, r->uri, name, ".gif", (long)st.size, "devgi0z", name); } } else if (query_string->mode == IMG_CONV_MODE_WALLPAPER && query_string->name != NULL) { if (query_string->count == -1 && query_string->offset == -1) { - ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS"); + chxj_set_content_type(r, "text/x-hdml; charset=Shift_JIS"); ap_rprintf(r, HDML_SUCCESS_PAGE); ap_rflush(r); } else if (query_string->count == -2 && query_string->offset == -1) { - ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS"); + chxj_set_content_type(r, "text/x-hdml; charset=Shift_JIS"); ap_rprintf(r, HDML_FAIL_PAGE); ap_rflush(r); } else { - ap_set_content_type(r, "application/x-up-download"); + chxj_set_content_type(r, "application/x-up-download"); contentLength = apr_psprintf(r->pool, "%ld", query_string->count); apr_table_setn(r->headers_out, "Content-Length", (const char*)contentLength); DBG(r, "Content-Length:[%d]", (int)st.size); rv = apr_file_open(&fout, tmpfile, - APR_READ | APR_BINARY, APR_OS_DEFAULT, r->pool); + APR_FOPEN_READ | APR_FOPEN_BINARY | APR_FOPEN_BUFFERED | APR_FOPEN_SHARELOCK | APR_FOPEN_SENDFILE_ENABLED, + APR_OS_DEFAULT, r->pool); if (rv != APR_SUCCESS) { DBG(r,"tmpfile open failed[%s]", tmpfile); @@ -1541,19 +1760,28 @@ s_send_cache_file(device_table* spec, query_string_param_t* query_string, reques static apr_status_t -s_send_original_file(request_rec* r, const char* originalfile) +s_send_original_file(request_rec *r, const char *originalfile) { apr_status_t rv; apr_finfo_t st; - apr_file_t* fout; + apr_file_t *fout; apr_size_t sendbyte = 0; rv = apr_stat(&st, originalfile, APR_FINFO_MIN, r->pool); if (rv != APR_SUCCESS) return HTTP_NOT_FOUND; + /* for mod_cache */ + { + apr_table_setn(r->headers_out, "Vary", "User-Agent"); + apr_table_setn(r->err_headers_out, "Vary", "User-Agent"); + ap_update_mtime(r, st.mtime); + ap_set_last_modified(r); + } + rv = apr_file_open(&fout, originalfile, - APR_READ | APR_BINARY, APR_OS_DEFAULT, r->pool); + APR_FOPEN_READ | APR_FOPEN_BINARY | APR_FOPEN_BUFFERED | APR_FOPEN_SHARELOCK | APR_FOPEN_SENDFILE_ENABLED, + APR_OS_DEFAULT, r->pool); if (rv != APR_SUCCESS) { DBG(r, "originalfile open failed[%s]", originalfile); return HTTP_NOT_FOUND; @@ -1567,116 +1795,181 @@ s_send_original_file(request_rec* r, const char* originalfile) return OK; } + static apr_status_t -s_header_only_cache_file(device_table* spec, query_string_param_t* query_string, request_rec* r, const char* tmpfile) +s_header_only_cache_file(device_table *spec, query_string_param_t *query_string, request_rec *r, const char *tmpfile) { apr_status_t rv; apr_finfo_t st; - char* contentLength; + char *contentLength; + mod_chxj_config *conf = ap_get_module_config(r->per_dir_config, &chxj_module); + + DBG(r, "REQ[%X] start s_header_only_cache_file()", TO_ADDR(r)); rv = apr_stat(&st, tmpfile, APR_FINFO_MIN, r->pool); - if (rv != APR_SUCCESS) + if (rv != APR_SUCCESS) { + DBG(r, "REQ[%X] end s_header_only_cache_file()", TO_ADDR(r)); return HTTP_NOT_FOUND; - - DBG(r, "mode:[%d]", query_string->mode); - DBG(r, "name:[%s]", query_string->name); - DBG(r, "offset:[%ld]", query_string->offset); - DBG(r, "count:[%ld]", query_string->count); - - if (spec->available_jpeg) { - r->content_type = apr_psprintf(r->pool, "image/jpeg"); - } - else - if (spec->available_png) { - r->content_type = apr_psprintf(r->pool, "image/png"); - } - else - if (spec->available_gif) { - r->content_type = apr_psprintf(r->pool, "image/gif"); - } - else - if (spec->available_bmp2 || spec->available_bmp4) { - r->content_type = apr_psprintf(r->pool, "image/bmp"); } + DBG(r, "REQ[%X] mode:[%d]", TO_ADDR(r), query_string->mode); + DBG(r, "REQ[%X] name:[%s]", TO_ADDR(r), query_string->name); + DBG(r, "REQ[%X] offset:[%ld]", TO_ADDR(r), query_string->offset); + DBG(r, "REQ[%X] count:[%ld]", TO_ADDR(r), query_string->count); + if (query_string->mode != IMG_CONV_MODE_EZGET && query_string->name == NULL) { contentLength = apr_psprintf(r->pool, "%d", (int)st.size); apr_table_setn(r->headers_out, "Content-Length", (const char*)contentLength); + + MagickWand *magick_wand = NewMagickWand(); + if (MagickReadImage(magick_wand,tmpfile) == MagickFalse) { + EXIT_MAGICK_ERROR(); + return HTTP_NOT_FOUND; + } + if (MagickStripImage(magick_wand) == MagickFalse) { + ERR(r, "mod_chxj: strip image failure."); + EXIT_MAGICK_ERROR(); + return HTTP_NOT_FOUND; + } + char *nowFormat = MagickGetImageFormat(magick_wand); + DestroyMagickWand(magick_wand); + if (nowFormat) { + if (STRCASEEQ('j','J',"jpeg",nowFormat) || STRCASEEQ('j','J',"jpg",nowFormat)) { + DBG(r, "detect cache file => jpg."); + ap_set_content_type(r, "image/jpeg"); + } + else if (STRCASEEQ('p','P',"png", nowFormat)) { + DBG(r, "detect cache file => png."); + ap_set_content_type(r, "image/png"); + } + else if (STRCASEEQ('g','G',"gif", nowFormat)) { + DBG(r, "detect cache file => gif."); + ap_set_content_type(r, "image/gif"); + } + else if (STRCASEEQ('b','B',"bmp", nowFormat)) { + DBG(r, "detect cache file => bmp."); + ap_set_content_type(r, "image/bmp"); + } + else { + ERR(r, "REQ[%X] detect unknown file", TO_ADDR(r)); + return HTTP_NOT_FOUND; + } + } DBG(r,"Content-Length:[%d]", (int)st.size); } else if (query_string->mode == IMG_CONV_MODE_EZGET) { - char* name = apr_pstrdup(r->pool, basename(r->filename)); + char *name = apr_pstrdup(r->pool, basename(r->filename)); name[strlen(name)-4] = 0; if (strcasecmp(r->content_type, "image/jpeg") == 0) { - ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS"); + chxj_set_content_type(r, "text/x-hdml; charset=Shift_JIS"); } else if (strcasecmp(r->content_type, "image/bmp") == 0) { - ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS"); + chxj_set_content_type(r, "text/x-hdml; charset=Shift_JIS"); } else if (strcasecmp(r->content_type, "image/png") == 0) { - ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS"); + chxj_set_content_type(r, "text/x-hdml; charset=Shift_JIS"); } else if (strcasecmp(r->content_type, "image/gif") == 0) { - ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS"); + chxj_set_content_type(r, "text/x-hdml; charset=Shift_JIS"); } } else if (query_string->mode == IMG_CONV_MODE_WALLPAPER && query_string->name != NULL) { if (query_string->count == -1 && query_string->offset == -1) { - ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS"); + chxj_set_content_type(r, "text/x-hdml; charset=Shift_JIS"); } else if (query_string->count == -2 && query_string->offset == -1) { - ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS"); + chxj_set_content_type(r, "text/x-hdml; charset=Shift_JIS"); } else { - ap_set_content_type(r, "application/x-up-download"); + chxj_set_content_type(r, "application/x-up-download"); contentLength = apr_psprintf(r->pool, "%ld", query_string->count); apr_table_setn(r->headers_out, "Content-Length", (const char*)contentLength); - DBG(r, "Content-Length:[%d]", (int)st.size); + DBG(r, "REQ[%X] Content-Length:[%d]", TO_ADDR(r), (int)st.size); + } + } + if (conf->image_copyright) { + DBG(r, "REQ[%X] Add COPYRIGHT Header for SoftBank [%s]", TO_ADDR(r), conf->image_copyright); + if (spec->html_spec_type == CHXJ_SPEC_Jhtml || spec->html_spec_type == CHXJ_SPEC_Jxhtml) { + apr_table_setn(r->headers_out, "x-jphone-copyright", "no-transfer"); } } + DBG(r, "REQ[%X] end s_header_only_cache_file()", TO_ADDR(r)); return OK; } +static void +s_init_serial_pattern(apr_pool_t *p) +{ + if (!v_docomo_serial_pattern1) { + v_docomo_serial_pattern1 = chxj_compile_for_preg_replace(p, "/ser[^;\\)]+"); + } + if (!v_docomo_serial_pattern2) { + v_docomo_serial_pattern2 = chxj_compile_for_preg_replace(p, ";ser[^;\\)]+"); + } + if (!v_docomo_serial_pattern3) { + v_docomo_serial_pattern3 = chxj_compile_for_preg_replace(p, ";icc[^;\\)]+"); + } + if (!v_softbank_serial_pattern1) { + v_softbank_serial_pattern1 = chxj_compile_for_preg_replace(p, "/SN[0-9a-zA-Z]+ "); + } +} + -static char* -s_create_workfile( - request_rec* r, - mod_chxj_config* conf, - const char* user_agent, +static char * +s_create_workfile_name( + request_rec *r, + mod_chxj_config *conf, + const char *user_agent, query_string_param_t *qsp) { - int ii; - int jj; - int len; - char* w = apr_palloc(r->pool, 256); - char* fname; + int ii; + int jj; + int len; + char *w = apr_palloc(r->pool, 256); + char *fname; + char *new_user_agent; + + s_init_serial_pattern(r->server->process->pool); + + /* for DoCoMo */ + new_user_agent = chxj_preg_replace(r->pool, v_docomo_serial_pattern1, "", user_agent); + new_user_agent = chxj_preg_replace(r->pool, v_docomo_serial_pattern2, "", new_user_agent); + new_user_agent = chxj_preg_replace(r->pool, v_docomo_serial_pattern3, "", new_user_agent); + + /* for SoftBank */ + new_user_agent = chxj_preg_replace(r->pool, v_softbank_serial_pattern1, " ", new_user_agent); + + DBG(r, "old user_agent:[%s] ==> new user_agent:[%s]", user_agent, new_user_agent); + memset(w, 0, 256); switch (qsp->mode) { case IMG_CONV_MODE_THUMBNAIL: - fname = apr_psprintf(r->pool, "%s.%s.thumbnail", r->filename, user_agent); + fname = apr_psprintf(r->pool, "%s.%s.thumbnail", r->filename, new_user_agent); DBG(r, "mode=thumbnail [%s]", fname); break; + case IMG_CONV_MODE_WALLPAPER: case IMG_CONV_MODE_EZGET: - fname = apr_psprintf(r->pool, "%s.%s.wallpaper", r->filename, user_agent); + fname = apr_psprintf(r->pool, "%s.%s.wallpaper", r->filename, new_user_agent); DBG(r, "mode=WallPaper [%s]", fname); break; + case IMG_CONV_MODE_NORMAL: default: - fname = apr_psprintf(r->pool, "%s.%s", r->filename, user_agent); + fname = apr_psprintf(r->pool, "%s.%s", r->filename, new_user_agent); if (qsp->width) fname = apr_psprintf(r->pool, "%s.w%d", fname, qsp->width); @@ -1709,8 +2002,9 @@ s_create_workfile( return apr_psprintf(r->pool, "%s/%s", conf->image_cache_dir,w); } + static unsigned short -s_add_crc(const char* writedata, apr_size_t writebyte) +s_add_crc(const char *writedata, apr_size_t writebyte) { unsigned short crc = 0xffff; apr_size_t ii; @@ -1723,34 +2017,40 @@ s_add_crc(const char* writedata, apr_size_t writebyte) return crc; } + int chxj_trans_name(request_rec *r) { - const char* ccp; - char* docroot; - int len; - apr_finfo_t st; - apr_status_t rv; - mod_chxj_config* conf; - int ii; - char* ext[] = { + const char *ccp; + char *docroot; + int len; + apr_finfo_t st; + apr_status_t rv; + mod_chxj_config *conf; + int ii; + char *ext[] = { "jpg", + "JPG", "jpeg", + "JPEG", "png", + "PNG", "bmp", + "BMP", "gif", - "qrc", /* QRCode½ÐÎÏÍÑ¥Õ¥¡¥¤¥ë¤Î³ÈÄ¥»Ò */ + "GIF", + "qrc", /* QRCode出力用ファイルの拡張子 */ "", }; - char* fname; - char* idx; - char* filename_sv; + char *fname = NULL; + char *idx; + char *filename_sv; int do_ext_check = TRUE; int next_ok = FALSE; DBG(r, "start chxj_trans_name()"); - conf = ap_get_module_config(r->per_dir_config, &chxj_module); + conf = chxj_get_module_config(r->per_dir_config, &chxj_module); if (conf == NULL) { DBG(r, "end chxj_trans_name() conf is null[%s]", r->uri); @@ -1798,7 +2098,7 @@ chxj_trans_name(request_rec *r) DBG(r,"URI[%s]", filename_sv); do_ext_check = TRUE; - for (ii=0; ii<7-1; ii++) { + for (ii=0; ii<(int)(sizeof(ext)/sizeof(ext[0])); ii++) { char* pos = strrchr(filename_sv, '.'); if (pos && pos++) { if (strcasecmp(pos, ext[ii]) == 0) { @@ -1810,7 +2110,7 @@ chxj_trans_name(request_rec *r) } if (do_ext_check) { - for (ii=0; ii<7; ii++) { + for (ii=0; ii<(int)(sizeof(ext)/sizeof(ext[0])); ii++) { if (strlen(ext[ii]) == 0) { fname = apr_psprintf(r->pool, "%s", filename_sv); } @@ -1832,7 +2132,7 @@ chxj_trans_name(request_rec *r) DBG(r,"NotFound [%s]", r->filename); return DECLINED; } - for (ii=0; ii<7-1; ii++) { + for (ii=0; ii<(int)(sizeof(ext)/sizeof(ext[0])); ii++) { char* pos = strrchr(fname, '.'); if (pos && pos++) { if (strcasecmp(pos, ext[ii]) == 0) { @@ -1863,21 +2163,139 @@ chxj_trans_name(request_rec *r) +static int +s_chxj_trans_name2(request_rec *r) +{ + apr_finfo_t st; + apr_status_t rv; + mod_chxj_config *conf; + int ii; + char *ext[] = { + "jpg", + "JPG", + "jpeg", + "JPEG", + "png", + "PNG", + "bmp", + "BMP", + "gif", + "GIF", + "qrc", /* QRCode出力用ファイルの拡張子 */ + "", + }; + char *fname = NULL; + char *filename_sv; + int do_ext_check = TRUE; + int next_ok = FALSE; + + DBG(r, "REQ[%X] start chxj_trans_name2()", (unsigned int)(apr_size_t)r); + + conf = chxj_get_module_config(r->per_dir_config, &chxj_module); + + if (conf == NULL) { + DBG(r, "REQ[%X] end chxj_trans_name2() conf is null[%s]", (unsigned int)(apr_size_t)r, r->uri); + return DECLINED; + } + + if (conf->image != CHXJ_IMG_ON) { + DBG(r, "REQ[%X] end chxj_trans_name2() ImageEngineOff", (unsigned int)(apr_size_t)r); + return DECLINED; + } + + + DBG(r,"Match URI[%s]", r->uri); + + if (r->filename == NULL) { + DBG(r, "REQ[%X] end chxj_trans_name2() r->filename is null", (unsigned int)(apr_size_t)r); + return DECLINED; + } + + filename_sv = r->filename; + + DBG(r,"REQ[%x] r->filename[%s]", (unsigned int)(apr_size_t)r, filename_sv); + + do_ext_check = TRUE; + for (ii=0; ii<(int)(sizeof(ext)/sizeof(ext[0])); ii++) { + char* pos = strrchr(filename_sv, '.'); + if (pos && pos++) { + if (strcasecmp(pos, ext[ii]) == 0) { + do_ext_check = FALSE; + fname = apr_psprintf(r->pool, "%s", filename_sv); + break; + } + } + } + + if (do_ext_check) { + for (ii=0; ii<(int)(sizeof(ext)/sizeof(ext[0])); ii++) { + if (strlen(ext[ii]) == 0) { + fname = apr_psprintf(r->pool, "%s", filename_sv); + } + else + fname = apr_psprintf(r->pool, "%s.%s", filename_sv, ext[ii]); + + DBG(r,"search [%s]", fname); + + rv = apr_stat(&st, fname, APR_FINFO_MIN, r->pool); + if (rv == APR_SUCCESS) { + if (st.filetype != APR_DIR) + break; + } + + fname = NULL; + } + } + if (fname == NULL) { + DBG(r,"NotFound [%s]", r->filename); + return DECLINED; + } + for (ii=0; ii<(int)(sizeof(ext)/sizeof(ext[0])); ii++) { + char* pos = strrchr(fname, '.'); + if (pos && pos++) { + if (strcasecmp(pos, ext[ii]) == 0) { + next_ok = TRUE; + break; + } + } + } + + if (! next_ok) { + DBG(r,"NotFound [%s]", r->filename); + return DECLINED; + } + + if (r->handler == NULL || strcasecmp(r->handler, "chxj-qrcode") != 0) { + DBG(r,"Found [%s]", fname); + + r->filename = apr_psprintf(r->pool, "%s", fname); + + if (strcasecmp("qrc", ext[ii]) == 0) + r->handler = apr_psprintf(r->pool, "chxj-qrcode"); + else + r->handler = apr_psprintf(r->pool, "chxj-picture"); + } + DBG(r, "REQ[%X] end chxj_trans_name()", (unsigned int)(apr_size_t)r); + return OK; +} + + + /** * It converts it from QUERYSTRING. * * @param r [i] */ -static query_string_param_t* +static query_string_param_t * s_get_query_string_param(request_rec *r) { - char* pair; - char* name; - char* value; - char* pstate; - char* vstate; - char* s; - query_string_param_t* param; + char *pair; + char *name; + char *value; + char *pstate; + char *vstate; + char *s; + query_string_param_t *param; s = apr_pstrdup(r->pool, r->parsed_uri.query); param = apr_palloc(r->pool, sizeof(query_string_param_t)); @@ -1981,6 +2399,85 @@ s_get_query_string_param(request_rec *r) return param; } + + +static char * +s_add_comment_to_png(request_rec *r, char *data, apr_size_t *len) +{ + char *result = NULL; +#define PNG_COPYRIGHT_KEY "Copyright" +#define PNG_COPYRIGHT_VAL "kddi_copyright=on,copy=NO" +#define PNG_SIG_AND_IHDR_SZ (33) + char *key = PNG_COPYRIGHT_KEY; + apr_size_t klen = sizeof(PNG_COPYRIGHT_KEY)-1; + char *val = PNG_COPYRIGHT_VAL; + apr_size_t vlen = sizeof(PNG_COPYRIGHT_VAL)-1; + apr_pool_t *pool; + apr_size_t total_tEXt_size; + apr_size_t tEXt_data_size; + apr_size_t pos; + apr_size_t ii; + char *buf; + char *valbuf; + uint32_t crc; + mod_chxj_config *conf = chxj_get_module_config(r->per_dir_config, &chxj_module); + + DBG(r, "REQ[%X] start s_add_comment_to_png()",(unsigned int)(apr_size_t)r); + if (conf->image_copyright) { + apr_pool_create(&pool, r->pool); + + valbuf = apr_psprintf(pool, "%s,%s", val, conf->image_copyright); + vlen = strlen(valbuf); + + /* total_size = length + "tEXt" + "Copyright" + '\0' + val + crc */ + total_tEXt_size = 4 + 4 + klen + vlen + 1 + 4; + result = apr_palloc(pool, total_tEXt_size + *len); + if (!result) { + DBG(r, "REQ[%X] memory allocation error.", (unsigned int)(apr_size_t)r); + return NULL; + } + pos = PNG_SIG_AND_IHDR_SZ; + memcpy(result, data, pos); /* 33 = SIGNATURE + IHDR */ + tEXt_data_size = klen + 1 + vlen; + result[pos + 0] = tEXt_data_size >> 24; + result[pos + 1] = tEXt_data_size >> 16; + result[pos + 2] = tEXt_data_size >> 8; + result[pos + 3] = tEXt_data_size; + pos += 4; + buf = apr_palloc(pool, 4 + klen + 1 + vlen); + memcpy(&buf[0], "tEXt", 4); + memcpy(&buf[4], key, klen); + buf[4+klen] = 0; + memcpy(&buf[4+klen+1], valbuf, vlen); + + + DBG(r, "REQ[%X] buf:[%s]", (unsigned int)(apr_size_t)r, buf); + + crc = 0xffffffff; + for (ii = 0; ii < 4 + tEXt_data_size; ii++) { + crc = AU_CRC_TBL[(crc ^ buf[ii]) & 0xff] ^ (crc >> 8); + } + crc ^= 0xffffffff; + memcpy(&result[pos], buf, 4 + klen + 1 + vlen); + pos += (4 + klen + 1 + vlen); + result[pos + 0] = crc >> 24; + result[pos + 1] = crc >> 16; + result[pos + 2] = crc >> 8; + result[pos + 3] = crc; + pos += 4; + memcpy(&result[pos], &data[PNG_SIG_AND_IHDR_SZ] , *len - PNG_SIG_AND_IHDR_SZ); + *len = *len + total_tEXt_size; + DBG(r, "REQ[%X] writebyte:[%d]", (unsigned int)(apr_size_t)r, (unsigned int)*len); + } + else { + result = data; + } + DBG(r, "REQ[%X] end s_add_comment_to_png()",(unsigned int)(apr_size_t)r); +#undef PNG_SIG_AND_IHDR_SZ +#undef PNG_COPYRIGHT_KEY +#undef PNG_COPYRIGHT_VAL + return result; +} /* * vim:ts=2 et */