OSDN Git Service

f1651d4eac1b0d848eac8aa61d77109ebda4e1a5
[modchxj/mod_chxj.git] / src / chxj_img_conv_format.c
1 /*
2  * Copyright (C) 2005-2011 Atsushi Konno All rights reserved.
3  * Copyright (C) 2005 QSDN,Inc. All rights reserved.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 #include <libgen.h>
18 #include <limits.h>
19 #include "mod_chxj.h"
20 #include "chxj_img_conv_format.h"
21 #include "chxj_specified_device.h"
22 #include "chxj_str_util.h"
23 #include "chxj_qr_code.h"
24 #include "chxj_apply_convrule.h"
25 #include "chxj_url_encode.h"
26 #include "qs_parse_string.h"
27 #include "chxj_preg_replace.h"
28
29 #include "http_core.h"
30
31 #include <wand/magick_wand.h>
32
33 /*
34  * @see htcacheclean
35  */
36 #define CACHEDATA_EXT "data"
37
38 #if !defined(LONG_LONG_MAX) && defined(LLONG_MAX)
39 #  define LONG_LONG_MAX LLONG_MAX
40 #endif
41
42 #define EXIT_MAGICK_ERROR() \
43   do { \
44     char *description; ExceptionType severity; \
45     description=MagickGetException(magick_wand,&severity); \
46     ap_log_rerror(APLOG_MARK,APLOG_ERR, 0, r,"%s %s %d %s\n",__FILE__,(__func__),__LINE__,description); \
47     description=(char *) MagickRelinquishMemory(description); \
48     DestroyMagickWand(magick_wand); \
49   } while(0) 
50
51 typedef enum img_conv_mode_t {
52   IMG_CONV_MODE_NORMAL = 0,
53   IMG_CONV_MODE_THUMBNAIL,
54   IMG_CONV_MODE_WALLPAPER,
55   IMG_CONV_MODE_EZGET,
56 } img_conv_mode_t;
57
58 /*----------------------------------------------------------------------------*/
59 /* User-Agent use flag                                                        */
60 /*----------------------------------------------------------------------------*/
61 typedef enum _ua_use_flag_t {
62   UA_USE=0,               /* User-Agent is used.                              */
63   UA_IGN,                 /* User-Agent is disregarded.                       */
64 } ua_use_flag_t;
65
66 /*----------------------------------------------------------------------------*/
67 /* Request parameter maintenance structure                                    */
68 /*----------------------------------------------------------------------------*/
69 typedef struct query_string_param_t query_string_param_t;
70
71 struct query_string_param_t {
72   img_conv_mode_t   mode;
73   char              *user_agent;
74   ua_use_flag_t     ua_flag;
75
76   char              *name;      /* for EZGET */
77   long              offset;    /* for EZGET */
78   long              count;     /* for EZGET */
79   int               width;
80   int               height;
81 };
82
83 /*----------------------------------------------------------------------------*/
84 /* Device_spec when User-Agent is disregarded                                 */
85 /*----------------------------------------------------------------------------*/
86 static device_table v_ignore_spec = {
87   NULL,
88   "IGN",
89   "IGN",
90   CHXJ_SPEC_HTML,
91   640,
92   480,
93   640,
94   480,
95   1024*1024,
96   1,
97   1,
98   1,
99   0,
100   0,
101   96,
102   96,
103   65536,
104   NULL,
105 };
106
107 /*----------------------------------------------------------------------------*/
108 /* CRC calculation table for AU                                               */
109 /*----------------------------------------------------------------------------*/
110 static unsigned short  AU_CRC_TBL[256] = {
111   0x0000,0x1021,0x2042,0x3063,0x4084,0x50A5,0x60C6,0x70E7,
112   0x8108,0x9129,0xA14A,0xB16B,0xC18C,0xD1AD,0xE1CE,0xF1EF,
113   0x1231,0x0210,0x3273,0x2252,0x52B5,0x4294,0x72F7,0x62D6,
114   0x9339,0x8318,0xB37B,0xA35A,0xD3BD,0xC39C,0xF3FF,0xE3DE,
115   0x2462,0x3443,0x0420,0x1401,0x64E6,0x74C7,0x44A4,0x5485,
116   0xA56A,0xB54B,0x8528,0x9509,0xE5EE,0xF5CF,0xC5AC,0xD58D,
117   0x3653,0x2672,0x1611,0x0630,0x76D7,0x66F6,0x5695,0x46B4,
118   0xB75B,0xA77A,0x9719,0x8738,0xF7DF,0xE7FE,0xD79D,0xC7BC,
119   0x48C4,0x58E5,0x6886,0x78A7,0x0840,0x1861,0x2802,0x3823,
120   0xC9CC,0xD9ED,0xE98E,0xF9AF,0x8948,0x9969,0xA90A,0xB92B,
121   0x5AF5,0x4AD4,0x7AB7,0x6A96,0x1A71,0x0A50,0x3A33,0x2A12,
122   0xDBFD,0xCBDC,0xFBBF,0xEB9E,0x9B79,0x8B58,0xBB3B,0xAB1A,
123   0x6CA6,0x7C87,0x4CE4,0x5CC5,0x2C22,0x3C03,0x0C60,0x1C41,
124   0xEDAE,0xFD8F,0xCDEC,0xDDCD,0xAD2A,0xBD0B,0x8D68,0x9D49,
125   0x7E97,0x6EB6,0x5ED5,0x4EF4,0x3E13,0x2E32,0x1E51,0x0E70,
126   0xFF9F,0xEFBE,0xDFDD,0xCFFC,0xBF1B,0xAF3A,0x9F59,0x8F78,
127   0x9188,0x81A9,0xB1CA,0xA1EB,0xD10C,0xC12D,0xF14E,0xE16F,
128   0x1080,0x00A1,0x30C2,0x20E3,0x5004,0x4025,0x7046,0x6067,
129   0x83B9,0x9398,0xA3FB,0xB3DA,0xC33D,0xD31C,0xE37F,0xF35E,
130   0x02B1,0x1290,0x22F3,0x32D2,0x4235,0x5214,0x6277,0x7256,
131   0xB5EA,0xA5CB,0x95A8,0x8589,0xF56E,0xE54F,0xD52C,0xC50D,
132   0x34E2,0x24C3,0x14A0,0x0481,0x7466,0x6447,0x5424,0x4405,
133   0xA7DB,0xB7FA,0x8799,0x97B8,0xE75F,0xF77E,0xC71D,0xD73C,
134   0x26D3,0x36F2,0x0691,0x16B0,0x6657,0x7676,0x4615,0x5634,
135   0xD94C,0xC96D,0xF90E,0xE92F,0x99C8,0x89E9,0xB98A,0xA9AB,
136   0x5844,0x4865,0x7806,0x6827,0x18C0,0x08E1,0x3882,0x28A3,
137   0xCB7D,0xDB5C,0xEB3F,0xFB1E,0x8BF9,0x9BD8,0xABBB,0xBB9A,
138   0x4A75,0x5A54,0x6A37,0x7A16,0x0AF1,0x1AD0,0x2AB3,0x3A92,
139   0xFD2E,0xED0F,0xDD6C,0xCD4D,0xBDAA,0xAD8B,0x9DE8,0x8DC9,
140   0x7C26,0x6C07,0x5C64,0x4C45,0x3CA2,0x2C83,0x1CE0,0x0CC1,
141   0xEF1F,0xFF3E,0xCF5D,0xDF7C,0xAF9B,0xBFBA,0x8FD9,0x9FF8,
142   0x6E17,0x7E36,0x4E55,0x5E74,0x2E93,0x3EB2,0x0ED1,0x1EF0 
143 };
144
145 /*----------------------------------------------------------------------------*/
146 /* Download page for AU                                                       */
147 /*----------------------------------------------------------------------------*/
148 static const char *HDML_FIRST_PAGE = 
149   "<HDML VERSION=3.0 TTL=0 PUBLIC=TRUE>\r\n"
150   "  <NODISPLAY>\r\n"
151   "    <ACTION TYPE=ACCEPT TASK=GOSUB DEST=\"device:data/dnld?url=%s&name=%s%s&size=%ld&disposition=%s&title=%s\">\r\n"
152   "  </NODISPLAY>\r\n"
153   "</HDML>\r\n";
154
155 static const char *HDML_SUCCESS_PAGE =
156   "<HDML VERSION=3.0 TTL=0 PUBLIC=TRUE>\r\n"
157   "  <DISPLAY>\r\n"
158   "    <ACTION TYPE=ACCEPT TASK=RETURN>\r\n"
159   "    \x83\x5f\x83\x45\x83\x93\x83\x8d\x81\x5b\x83\x68\x82\xc9\x90\xac\x8c\xf7\x82\xb5\x82\xdc\x82\xb5\x82\xbd\r\n"
160   "  </DISPLAY>\r\n"
161   "<HDML>\r\n";
162
163 static const char *HDML_FAIL_PAGE =
164   "<HDML VERSION=3.0 TTL=0 PUBLIC=TRUE>\r\n"
165   "  <DISPLAY>\r\n"
166   "    <ACTION TYPE=ACCEPT TASK=RETURN>\r\n"
167   "    \x83\x5f\x83\x45\x83\x93\x83\x8d\x81\x5b\x83\x68\x82\xc9\x8e\xb8\x94\x73\x82\xb5\x82\xdc\x82\xb5\x82\xbd\r\n"
168   "  </DISPLAY>\r\n"
169   "<HDML>\r\n";
170
171 static ap_regex_t *v_docomo_serial_pattern1 = NULL;
172 static ap_regex_t *v_docomo_serial_pattern2 = NULL;
173 static ap_regex_t *v_docomo_serial_pattern3 = NULL;
174 static ap_regex_t *v_softbank_serial_pattern1 = NULL;
175
176 /*----------------------------------------------------------------------------*/
177 /* Prototype declaration                                                      */
178 /*----------------------------------------------------------------------------*/
179 static char *s_create_workfile_name(request_rec *, 
180                                     mod_chxj_config *, 
181                                     const char *,
182                                     query_string_param_t *);
183
184 static apr_status_t s_create_cache_file(request_rec          *r, 
185                                         const char           *tmpfile, 
186                                         device_table         *spec,
187                                         apr_finfo_t          *st,
188                                         query_string_param_t *qsp,
189                                         mod_chxj_config      *conf);
190
191 static apr_status_t s_send_cache_file(mod_chxj_config       *conf,
192                                       device_table          *spec,
193                                       query_string_param_t  *query_string,
194                                       request_rec           *r,
195                                       const char            *tmpfile);
196
197 static apr_status_t s_send_original_file(request_rec *r, 
198                                          const char  *originalfile);
199
200 static apr_status_t s_header_only_cache_file(device_table         *spec, 
201                                              query_string_param_t *query_string, 
202                                              request_rec          *r, 
203                                              const char           *tmpfile);
204
205 static query_string_param_t *s_get_query_string_param(request_rec *r);
206
207 static unsigned short s_add_crc(const char *writedata, apr_size_t witebyte);
208
209 static MagickWand *s_fixup_size(MagickWand   *, 
210                                 request_rec  *r, 
211                                 device_table *spec, 
212                                 query_string_param_t *qsp);
213
214 static MagickWand *s_fixup_color(MagickWand *magick_wand, 
215                                  request_rec *r, 
216                                  device_table *spec, 
217                                  img_conv_mode_t mode);
218 static MagickWand *s_fixup_depth(MagickWand* magick_wand, 
219                                  request_rec* r, device_table* spec);
220 static MagickWand *s_img_down_sizing(MagickWand *magick_wand, 
221                                 request_rec *r, device_table *spec);
222
223 static MagickWand *s_add_copyright(MagickWand *magick_wand,
224                                    request_rec *r,
225                                    device_table *spec);
226
227 static char *s_create_blob_data(request_rec *r,
228                                 device_table *spec,
229                                 query_string_param_t *qsp,
230                                 char *indata,
231                                 apr_size_t *len);
232
233 static int s_img_conv_format_from_file(request_rec          *r, 
234                                        mod_chxj_config      *conf, 
235                                        const char           *user_agent,
236                                        query_string_param_t *qsp,
237                                        device_table         *spec);
238 static int s_convert_to_jpeg(MagickWand *magick_wand, request_rec *r, device_table *spec);
239 static int s_convert_to_png(MagickWand *maigck_wand, request_rec *r, device_table *spec);
240 static int s_convert_to_gif(MagickWand *magick_wand, request_rec *r, device_table *spec);
241 static int s_convert_to_bmp(MagickWand *magick_wand, request_rec *r, device_table *spec);
242 static int s_chxj_trans_name2(request_rec *r);
243 static char *s_add_comment_to_png(request_rec *r, char *data, apr_size_t *len);
244
245
246
247 int 
248 chxj_img_conv_format_handler(request_rec *r)
249 {
250   mod_chxj_config       *conf;
251   query_string_param_t  *qsp;
252   char                  *user_agent;
253   device_table          *spec;
254   chxjconvrule_entry    *entryp;
255   int                   rtn;
256
257   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
258
259   s_chxj_trans_name2(r);
260   
261   if (! r->handler || 
262       (r->handler && !STRCASEEQ('c','C',"chxj-picture",r->handler) && !STRCASEEQ('c','C',"chxj-qrcode",r->handler))) {
263     DBG(r, "REQ[%X] Response Code:[%d]", TO_ADDR(r), r->status);
264     DBG(r, "REQ[%X] r->handler is[%s]", TO_ADDR(r), r->handler);
265     DBG(r, "REQ[%X] end %s()",TO_ADDR(r),__func__);
266     return DECLINED;
267   }
268
269   qsp = s_get_query_string_param(r);
270   conf = chxj_get_module_config(r->per_dir_config, &chxj_module);
271   if (conf == NULL) {
272     DBG(r,"REQ[%X] conf is null",TO_ADDR(r));
273     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
274     return DECLINED;
275   }
276
277   if (STRCASEEQ('c','C',"chxj-qrcode",r->handler) && conf->image == CHXJ_IMG_OFF) {
278     DBG(r,"REQ[%X] chxj-qrcode and ImageEngineOff", TO_ADDR(r));
279     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
280     return DECLINED;
281   }
282
283   /*------------------------------------------------------------------------*/
284   /* get UserAgent from http header                                         */
285   /*------------------------------------------------------------------------*/
286   /*--------------------------------------------------------------------------*/
287   /* User-Agent to spec                                                       */
288   /*--------------------------------------------------------------------------*/
289   if (qsp->user_agent) {
290     user_agent = apr_pstrdup(r->pool, qsp->user_agent);
291   }
292   else {
293     entryp = chxj_apply_convrule(r, conf->convrules);
294     if (entryp && entryp->user_agent) {
295       user_agent = (char*)apr_table_get(r->headers_in, CHXJ_HTTP_USER_AGENT);
296     }
297     else {
298       user_agent = (char*)apr_table_get(r->headers_in, HTTP_USER_AGENT);
299     }
300   }
301
302
303
304   if (qsp->ua_flag == UA_IGN)
305     spec = &v_ignore_spec;
306   else
307     spec = chxj_specified_device(r, user_agent);
308
309   DBG(r,"REQ[%X] found device_name=[%s]", TO_ADDR(r), spec->device_name);
310   DBG(r,"REQ[%X] User-Agent=[%s]", TO_ADDR(r), user_agent);
311
312
313   rtn = s_img_conv_format_from_file(r, conf, user_agent, qsp, spec);
314   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
315   return rtn;
316 }
317
318
319
320 /**
321  * It converts it from ImageData corresponding to each model.
322  *
323  * @param r   [i]
324  * @param src [i]   It is former image binary data.
325  * @param len [i/o] It is length of former image binary data.
326  */
327 char *
328 chxj_convert_image(request_rec *r, const char **src, apr_size_t *len)
329 {
330   mod_chxj_config       *conf;
331   query_string_param_t  *qsp;
332   char                  *user_agent;
333   device_table          *spec;
334   char                  *dst;
335   char                  *conv_check;
336   chxjconvrule_entry    *entryp;
337
338   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
339
340   conv_check = (char*)apr_table_get(r->headers_in, "CHXJ_IMG_CONV");
341   if (conv_check) {
342     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
343     return NULL;
344   }
345
346
347   qsp = s_get_query_string_param(r);
348   conf = chxj_get_module_config(r->per_dir_config, &chxj_module);
349   if (conf == NULL) {
350     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
351     return NULL;
352   }
353
354   /*--------------------------------------------------------------------------*/
355   /* User-Agent to spec                                                       */
356   /*--------------------------------------------------------------------------*/
357   if (qsp->user_agent) {
358     user_agent = apr_pstrdup(r->pool, qsp->user_agent);
359   }
360   else {
361     entryp = chxj_apply_convrule(r, conf->convrules);
362     if (entryp && entryp->user_agent) {
363       user_agent = (char*)apr_table_get(r->headers_in, CHXJ_HTTP_USER_AGENT);
364     }
365     else {
366       user_agent = (char*)apr_table_get(r->headers_in, HTTP_USER_AGENT);
367     }
368   }
369
370   if (qsp->ua_flag == UA_IGN)
371     spec = &v_ignore_spec;
372   else
373     spec = chxj_specified_device(r, user_agent);
374
375   DBG(r,"REQ[%X] found device_name=[%s]", TO_ADDR(r),spec->device_name);
376   DBG(r, "REQ[%X] User-Agent=[%s]", TO_ADDR(r),user_agent);
377
378   if (spec->width == 0 || spec->heigh == 0) {
379     DBG(r,"REQ[%X] not convert (width or height is 0)", TO_ADDR(r));
380     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
381     return NULL;
382   }
383
384   dst = s_create_blob_data(r, spec, qsp, (char*)*src, len);
385   if (dst == NULL) 
386     *len = 0;
387
388   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
389
390   return dst;
391 }
392
393
394 static int
395 s_img_conv_format_from_file(
396                 request_rec          *r, 
397                 mod_chxj_config      *conf, 
398                 const char           *user_agent,
399                 query_string_param_t *qsp,
400                 device_table         *spec)
401 {
402   apr_status_t   rv;
403   apr_finfo_t    st;
404   apr_finfo_t    cache_st;
405   char           *tmpfile;
406   int            try_count;
407
408   if (spec->html_spec_type == CHXJ_SPEC_UNKNOWN) {
409     /* 
410      * If ``ua'' parameter is specified, it must be CHXJ_SPEC_HTML. 
411      */
412     return s_send_original_file(r, r->filename);
413   }
414
415   /*--------------------------------------------------------------------------*/
416   /* Create Workfile Name                                                     */
417   /*--------------------------------------------------------------------------*/
418   tmpfile = s_create_workfile_name(r, conf, user_agent, qsp);
419   DBG(r,"REQ[%X] workfile=[%s]", TO_ADDR(r), tmpfile);
420
421   rv = apr_stat(&st, r->filename, APR_FINFO_MIN, r->pool);
422   if (rv != APR_SUCCESS)
423     return HTTP_NOT_FOUND;
424
425   apr_table_setn(r->headers_in, "CHXJ_IMG_CONV", "done");
426   try_count = CACHE_RETRY_COUNT;
427   do {
428     rv = apr_stat(&cache_st, tmpfile, APR_FINFO_MIN, r->pool);
429   
430     if (rv != APR_SUCCESS || cache_st.ctime < st.mtime) {
431       /*------------------------------------------------------------------------*/
432       /* It tries to make the cash file when it doesn't exist or there is       */
433       /* change time later since the making time of the cash file.              */
434       /*------------------------------------------------------------------------*/
435       rv = s_create_cache_file(r,tmpfile, spec, &st, qsp, conf);
436       if (rv != OK)
437         return rv;
438     }
439   
440     DBG(r,"REQ[%X] color=[%d]", TO_ADDR(r), spec->color);
441     if (! r->header_only)  {
442       rv = s_send_cache_file(conf, spec, qsp,r, tmpfile);
443     }
444     else {
445       rv = s_header_only_cache_file(spec, qsp, r, tmpfile);
446     }
447     if (rv == OK) break;
448     if (rv == HTTP_NOT_FOUND) {
449       DBG(r, "REQ[%X] recheck wait... try_count[%d]", TO_ADDR(r),try_count);
450       apr_sleep(CACHE_RECHECK_WAIT);
451     }
452   } while (try_count--); 
453   if (try_count <= 0) {
454     WRN(r, "REQ[%X] cache retry failure....", TO_ADDR(r));
455     WRN(r, "REQ[%X] cache file was deleted...",TO_ADDR(r));
456   }
457
458   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
459
460   return rv;
461 }
462
463
464 static apr_status_t
465 s_create_cache_file(request_rec          *r, 
466                     const char           *tmpfile, 
467                     device_table         *spec, 
468                     apr_finfo_t          *st, 
469                     query_string_param_t *qsp,
470                     mod_chxj_config      *conf)
471 {
472   apr_status_t       rv;
473   apr_size_t         readbyte;
474   apr_size_t         writebyte;
475   unsigned short     crc;
476   img_conv_mode_t    mode = qsp->mode;
477
478   char *writedata = NULL;
479   char *readdata  = NULL;
480
481   apr_file_t  *fout;
482   apr_file_t  *fin;
483   apr_finfo_t cache_dir_st;
484
485   MagickWand *magick_wand;
486   int        img_count;
487
488   if (STRCASEEQ('c','C',"chxj-qrcode",r->handler)) {
489     /*------------------------------------------------------------------------*/
490     /* QRCODE用のファイルの場合                                               */
491     /*------------------------------------------------------------------------*/
492     Doc       doc;
493     Node      *root;
494     qr_code_t qrcode;
495     int       sts;
496
497     memset(&doc,    0, sizeof(Doc));
498     memset(&qrcode, 0, sizeof(qr_code_t));
499     doc.r = r;
500     doc.parse_mode  = PARSE_MODE_CHTML;
501     qrcode.doc      = &doc;
502     qrcode.r        = r;
503
504     qs_init_malloc(&doc);
505
506     root = qs_parse_file(&doc, r->filename);
507
508     chxj_qrcode_node_to_qrcode(&qrcode, root);
509
510     qs_all_free(&doc,QX_LOGMARK);
511
512     sts = chxj_qrcode_create_image_data(&qrcode, &readdata, &readbyte);
513     if (sts != OK) {
514       ERR(r, "qrcode create failed.");
515       return sts;
516     }
517   }
518   else {
519     /*------------------------------------------------------------------------*/
520     /* 通常のイメージファイルの場合                                           */
521     /*------------------------------------------------------------------------*/
522     rv = apr_file_open(&fin, 
523                     r->filename, 
524                     APR_FOPEN_READ | APR_FOPEN_BINARY | APR_FOPEN_BUFFERED | APR_FOPEN_SHARELOCK | APR_FOPEN_SENDFILE_ENABLED,
525                     APR_OS_DEFAULT, 
526                     r->pool);
527     if (rv != APR_SUCCESS) {
528       ERR(r,"REQ[%X] %s:%d file open failed.[%s]", TO_ADDR(r),__FILE__,__LINE__,r->filename);
529       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
530       return HTTP_NOT_FOUND;
531     }
532   
533     readdata = apr_palloc(r->pool, st->size);
534     rv = apr_file_read_full(fin, (void*)readdata, st->size, &readbyte);
535     if (rv != APR_SUCCESS || readbyte != st->size) {
536       ERR(r,"REQ[%X] %s:%d file read failed.[%s]", TO_ADDR(r), __FILE__,__LINE__,r->filename);
537       apr_file_close(fin);
538   
539       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
540       return HTTP_NOT_FOUND;
541     }
542   }
543   DBG(r,"REQ[%X] start img convert", TO_ADDR(r));
544
545
546   magick_wand = NewMagickWand();
547   if (MagickReadImageBlob(magick_wand,readdata, readbyte) == MagickFalse) {
548     EXIT_MAGICK_ERROR();
549     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
550     return HTTP_NOT_FOUND;
551   }
552
553   /*------------------*/
554   /* for AnimationGIF */
555   /*------------------*/
556   img_count = MagickGetNumberImages(magick_wand);
557   DBG(r, "REQ[%X] img_count is [%d]", (unsigned int)(apr_size_t)r, img_count);
558   if (img_count > 1) {
559     MagickSetImageIndex(magick_wand, 0);
560     MagickWand *magick_wand2 = MagickGetImage(magick_wand);
561     DestroyMagickWand(magick_wand);
562     magick_wand = magick_wand2;
563   }
564
565   if (MagickStripImage(magick_wand) == MagickFalse) {
566     ERR(r, "REQ[%X] %s:%d mod_chxj: strip image failure.",TO_ADDR(r),__FILE__,__LINE__);
567     EXIT_MAGICK_ERROR();
568     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
569     return HTTP_NOT_FOUND;
570   }
571   {
572     MagickWand *magick_wand2;
573     if ((magick_wand2 = MagickCoalesceImages(magick_wand)) == NULL) {
574       EXIT_MAGICK_ERROR();
575       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
576       return HTTP_NOT_FOUND;
577     }
578     DestroyMagickWand(magick_wand);
579     magick_wand = magick_wand2;
580   }
581
582   if (spec->html_spec_type != CHXJ_SPEC_UNKNOWN) {
583     int oldw = MagickGetImageWidth(magick_wand);
584     int oldh = MagickGetImageHeight(magick_wand);
585     int done_fixup_size = 0;
586     if ((qsp->mode == IMG_CONV_MODE_WALLPAPER && spec->wp_width < oldw && spec->wp_heigh < oldh)
587       || (qsp->mode != IMG_CONV_MODE_WALLPAPER && spec->width < oldw && spec->heigh < oldh)) {
588       /*
589        * The size of the image is changed.
590        */
591       DBG(r,"REQ[%X] call s_fixup_size()", TO_ADDR(r));
592   
593       if ((magick_wand = s_fixup_size(magick_wand, r, spec, qsp)) == NULL) 
594         return HTTP_NOT_FOUND;
595
596       done_fixup_size = 1;
597     }
598     /*
599      * The colors of the image is changed.
600      */
601     DBG(r,"REQ[%X] call s_fixup_color()", TO_ADDR(r));
602   
603     if ((magick_wand = s_fixup_color(magick_wand, r,spec, mode)) == NULL) {
604       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
605       return HTTP_NOT_FOUND;
606     }
607   
608     /*
609      * DEPTH of the image is changed.
610      */
611     DBG(r,"REQ[%X] call s_fixup_depth()", TO_ADDR(r));
612   
613     if ((magick_wand = s_fixup_depth(magick_wand, r, spec)) == NULL) {
614       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
615       return HTTP_NOT_FOUND;
616     }
617   
618   
619     if (! done_fixup_size) {
620       /*
621        * The size of the image is changed.
622        */
623       DBG(r,"REQ[%X] call s_fixup_size()", TO_ADDR(r));
624       if ((magick_wand = s_fixup_size(magick_wand, r, spec, qsp)) == NULL) {
625         DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
626         return HTTP_NOT_FOUND;
627       }
628     }
629
630     char *nowFormat = MagickGetImageFormat(magick_wand);
631     int fixFormatFlag = 0;
632     if (nowFormat) {
633       if (STRCASEEQ('g','G',"gif",nowFormat)) {
634         if (spec->available_gif) {
635           if (s_convert_to_gif(magick_wand, r, spec)) {
636             DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
637             return HTTP_NOT_FOUND;
638           }
639           fixFormatFlag = 1;
640         }
641       }
642       else if (STRCASEEQ('j','J',"jpg",nowFormat)||STRCASEEQ('j','J',"jpeg",nowFormat)) {
643         if (spec->available_jpeg) {
644           if (s_convert_to_jpeg(magick_wand, r, spec)) {
645             DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
646             return HTTP_NOT_FOUND;
647           }
648           fixFormatFlag = 1;
649         }
650       }
651       else if (STRCASEEQ('p','P',"png",nowFormat)) {
652         if (spec->available_png) {
653           if (s_convert_to_png(magick_wand, r, spec)) {
654             DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
655             return HTTP_NOT_FOUND;
656           }
657           fixFormatFlag = 1;
658         }
659       }
660       else if (STRCASEEQ('b','B',"bmp",nowFormat)) {
661         if (spec->available_bmp4 || spec->available_bmp2) {
662           if (s_convert_to_bmp(magick_wand, r, spec)) {
663             DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
664             return HTTP_NOT_FOUND;
665           }
666           fixFormatFlag = 1;
667         }
668       }
669     }
670
671     DBG(r,"REQ[%X] start convert and compression", TO_ADDR(r));
672   
673     if (! fixFormatFlag) {
674       if (spec->available_jpeg) {
675         if (s_convert_to_jpeg(magick_wand, r, spec)) {
676           DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
677           return HTTP_NOT_FOUND;
678         }
679       }
680       else if (spec->available_gif) {
681         if (s_convert_to_gif(magick_wand, r, spec)) {
682           DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
683           return HTTP_NOT_FOUND;
684         }  
685       }
686       else if (spec->available_png) {
687         if (s_convert_to_png(magick_wand, r, spec)) {
688           DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
689           return HTTP_NOT_FOUND;
690         }  
691   
692       }
693       else
694       if (spec->available_bmp2 || spec->available_bmp4) { 
695         if (s_convert_to_bmp(magick_wand, r, spec)) {
696           DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
697           return HTTP_NOT_FOUND;
698         }
699       }
700     }
701   
702     /*
703      * Add Comment (Copyright and so on.)
704      */
705     DBG(r, "call s_add_copyright()");
706   
707     if ((magick_wand = s_add_copyright(magick_wand, r, spec)) == NULL) {
708       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
709       return HTTP_NOT_FOUND;
710     }
711   }
712   else {
713     char* fmt;
714     fmt = MagickGetImageFormat(magick_wand);
715     if (fmt == NULL) {
716       if (MagickSetImageFormat(magick_wand, "jpg") == MagickFalse) {
717         EXIT_MAGICK_ERROR();
718         DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
719         return HTTP_NOT_FOUND;
720       }
721   
722       r->content_type = apr_psprintf(r->pool, "image/jpeg");
723     }
724     else {
725       if (strcasecmp(fmt, "jpg") == 0) {
726         r->content_type = apr_psprintf(r->pool, "image/jpeg");
727       }
728       else
729       if (strcasecmp(fmt, "jpeg") == 0) {
730         r->content_type = apr_psprintf(r->pool, "image/jpeg");
731       }
732       else
733       if (strcasecmp(fmt, "gif") == 0) {
734         r->content_type = apr_psprintf(r->pool, "image/gif");
735       }
736       else
737       if (strcasecmp(fmt, "png") == 0) {
738         r->content_type = apr_psprintf(r->pool, "image/png");
739       }
740     }
741   }
742
743   char *sv_writedata;
744   sv_writedata = writedata = (char*)MagickGetImageBlob(magick_wand, &writebyte);
745
746   if (! writebyte) {
747     DestroyMagickWand(magick_wand);
748     ERR(r,"REQ[%X] convert failure to Jpeg [%s]", TO_ADDR(r),tmpfile);
749     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
750     return HTTP_INTERNAL_SERVER_ERROR;
751   }
752   writedata = apr_palloc(r->pool, writebyte);
753   memcpy(writedata, sv_writedata, writebyte);
754
755   DBG(r, "REQ[%X] end convert and compression",TO_ADDR(r));
756
757   /* Added PNG Comment if type is image/png. */
758   if (r->content_type && strcmp(r->content_type, "image/png") == 0) {
759     if ((writedata = s_add_comment_to_png(r, writedata, &writebyte)) == NULL) {
760       ERR(r, "REQ[%X] Add comment to PNG failure.",TO_ADDR(r));
761       DestroyMagickWand(magick_wand);
762       if (sv_writedata) free(sv_writedata);
763       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
764       return HTTP_INTERNAL_SERVER_ERROR;
765     }
766   }
767   
768   /* check limit */
769   rv = apr_stat(&cache_dir_st, conf->image_cache_dir, APR_FINFO_MIN, r->pool);
770   if (rv != APR_SUCCESS) {
771     DestroyMagickWand(magick_wand);
772     ERR(r,"REQ[%X] dir stat error.[%s]", TO_ADDR(r),conf->image_cache_dir);
773     if (sv_writedata) free(sv_writedata);
774     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
775     return HTTP_INTERNAL_SERVER_ERROR;
776   }
777   
778   for (;;) {
779     /* delete candidate */
780     apr_finfo_t dcf;   
781     /* get dir files size */
782     apr_dir_t *dir;
783     unsigned long total_size = 0;
784     int found_file = 0;
785     unsigned long max_size = (! conf->image_cache_limit) ? DEFAULT_IMAGE_CACHE_LIMIT : conf->image_cache_limit;
786     char *delete_file_name;
787
788     rv = apr_dir_open(&dir, conf->image_cache_dir, r->pool);
789     if (rv != APR_SUCCESS) { 
790       DestroyMagickWand(magick_wand);
791       ERR(r,"REQ[%X] %s:%d dir open error.[%s]", TO_ADDR(r),__FILE__,__LINE__,conf->image_cache_dir);
792       if (sv_writedata) free(sv_writedata);
793       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
794       return HTTP_INTERNAL_SERVER_ERROR;
795     }
796     memset(&dcf, 0, sizeof(apr_finfo_t));
797     dcf.atime = (apr_time_t)LONG_LONG_MAX;
798     for (;;) {
799       apr_finfo_t dirf;
800       rv = apr_dir_read(&dirf, APR_FINFO_SIZE|APR_FINFO_NAME|APR_FINFO_DIRENT|APR_FINFO_ATIME , dir);
801       if (rv != APR_SUCCESS) {
802         break;
803       }
804       if (dirf.name && strcmp(dirf.name, ".") != 0 && strcmp(dirf.name, "..") != 0) {
805         total_size += (unsigned long)dirf.size;
806         DBG(r, "REQ[%X] dirf.name=[%s] dirf.size=[%ld] dirf.atime=[%lld]", TO_ADDR(r),dirf.name, (long)dirf.size, (long long int)dirf.atime);
807         if (dcf.atime >= dirf.atime) {
808           memcpy(&dcf, &dirf, sizeof(apr_finfo_t));
809         }
810         found_file++;
811       }
812     }
813     apr_dir_close(dir);
814     if (total_size + writebyte < max_size) {
815       DBG(r, "REQ[%X] There is an enough size in cache. total_size:[%lu] max_size:[%lu] found_file=[%d] max_size=[%lu]", 
816              TO_ADDR(r),total_size, max_size, found_file, max_size);
817       break;
818     }
819     if (found_file == 0 && writebyte >= max_size) {
820       ERR(r, "REQ[%X] ==========================================", TO_ADDR(r));
821       ERR(r, "REQ[%X] cache space is too small...",TO_ADDR(r));
822       ERR(r, "REQ[%X] At least the same size as %luByte is necessary for me.", TO_ADDR(r),(unsigned long)writebyte); 
823       ERR(r, "REQ[%X] Please specify the ChxjImageCacheLimit that is larger than now value. ",TO_ADDR(r));
824       ERR(r, "REQ[%X] ==========================================",TO_ADDR(r));
825       if (sv_writedata) free(sv_writedata);
826       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
827       return HTTP_INTERNAL_SERVER_ERROR;
828     }
829     DBG(r, "REQ[%X] Image Cache dir is full. total_size:[%lu] max_size:[%lu]", TO_ADDR(r),total_size + writebyte, max_size);
830     /* search delete candidate */
831     delete_file_name = apr_psprintf(r->pool, "%s/%s", conf->image_cache_dir, dcf.name);
832     DBG(r, "REQ[%X] delete image cache target:[%s] atime:[%lld]", TO_ADDR(r),delete_file_name, (long long int)dcf.atime);
833     rv = apr_file_remove(delete_file_name, r->pool);
834     if (rv != APR_SUCCESS) {
835       ERR(r, "REQ[%X] %s:%d cache file delete failure.[%s]", TO_ADDR(r),__FILE__,__LINE__,delete_file_name);
836       if (sv_writedata) free(sv_writedata);
837       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
838       return HTTP_INTERNAL_SERVER_ERROR;
839     }
840     DBG(r, "REQ[%X] deleted image cache target:[%s]", TO_ADDR(r),delete_file_name);
841     if (total_size + writebyte - dcf.size < max_size) {
842       DBG(r, "REQ[%X] OK, there is an enough size in cache.",TO_ADDR(r));
843       break;
844     }
845   }
846
847   /* to cache */
848   rv = apr_file_open(&fout, tmpfile,
849                   APR_FOPEN_WRITE| APR_FOPEN_CREATE | APR_FOPEN_BINARY | APR_SHARELOCK ,
850                   APR_OS_DEFAULT, r->pool);
851   if (rv != APR_SUCCESS) {
852     DestroyMagickWand(magick_wand);
853     ERR(r,"REQ[%X] %s:%d file open error.[%s]", TO_ADDR(r),__FILE__,__LINE__,tmpfile);
854     if (sv_writedata) free(sv_writedata);
855     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
856     return HTTP_INTERNAL_SERVER_ERROR;
857   }
858
859   rv = apr_file_write(fout, (void*)writedata, &writebyte);
860   if (rv != APR_SUCCESS) {
861     ERR(r,"REQ[%X] %s:%d file write error.[%s]", TO_ADDR(r), __FILE__,__LINE__,tmpfile);
862     DestroyMagickWand(magick_wand);
863     apr_file_close(fout);
864     if (sv_writedata) free(sv_writedata);
865     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
866     return HTTP_INTERNAL_SERVER_ERROR;
867   }
868
869   /*
870    * CRC is added for AU for EzGET.
871    */
872   if (spec->html_spec_type == CHXJ_SPEC_XHtml_Mobile_1_0
873   ||  spec->html_spec_type == CHXJ_SPEC_Hdml            ) {
874
875     crc = s_add_crc(writedata, writebyte);
876
877     rv = apr_file_putc((crc >> 8)  & 0xff, fout);
878     if (rv != APR_SUCCESS) {
879       ERR(r,"REQ[%X] %s:%d file write error.[%s]", TO_ADDR(r), __FILE__,__LINE__,tmpfile);
880       DestroyMagickWand(magick_wand);
881       if (sv_writedata) free(sv_writedata);
882       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
883       return HTTP_INTERNAL_SERVER_ERROR;
884     }
885
886     rv = apr_file_putc( crc        & 0xff, fout);
887     if (rv != APR_SUCCESS) {
888       ERR(r,"REQ[%X] %s:%d file write error.[%s]", TO_ADDR(r), __FILE__,__LINE__,tmpfile);
889       DestroyMagickWand(magick_wand);
890       if (sv_writedata) free(sv_writedata);
891       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
892       return HTTP_INTERNAL_SERVER_ERROR;
893     }
894   }
895
896   DestroyMagickWand(magick_wand);
897   if (sv_writedata) free(sv_writedata);
898
899   rv = apr_file_close(fout);
900   if (rv != APR_SUCCESS) {
901     ERR(r,"REQ[%X] %s:%d file write error.[%s]", TO_ADDR(r), __FILE__,__LINE__,tmpfile);
902     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
903     return HTTP_INTERNAL_SERVER_ERROR;
904   }
905
906   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
907   return OK;
908 }
909
910
911 static int
912 s_convert_to_jpeg(MagickWand *magick_wand, request_rec *r, device_table *spec) 
913 {
914   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
915   if (MagickSetImageCompression(magick_wand,JPEGCompression) == MagickFalse) {
916     EXIT_MAGICK_ERROR();
917     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
918     return -1;
919   }
920   
921   if (MagickSetImageFormat(magick_wand, "jpg") == MagickFalse) {
922     EXIT_MAGICK_ERROR();
923     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
924     return -1;
925   }
926   
927   if (MagickStripImage(magick_wand) == MagickFalse) {
928     EXIT_MAGICK_ERROR();
929     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
930     return -1;
931   }
932   
933   if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL) {
934     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
935     return -1;
936   }
937   
938   r->content_type = apr_psprintf(r->pool, "image/jpeg");
939   ap_set_content_type(r, "image/jpeg");
940   DBG(r,"REQ[%X] convert to jpg", TO_ADDR(r));
941   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
942   return 0;
943 }
944
945
946 static int
947 s_convert_to_png(MagickWand *magick_wand, request_rec *r, device_table *spec)
948 {
949   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
950   if (MagickSetImageCompression(magick_wand,ZipCompression) == MagickFalse) {
951     EXIT_MAGICK_ERROR();
952     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
953     return -1;
954   }
955   
956   if (MagickSetImageFormat(magick_wand, "png") == MagickFalse) {
957     EXIT_MAGICK_ERROR();
958     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
959     return -1;
960   }
961   
962   if (MagickStripImage(magick_wand) == MagickFalse) {
963     EXIT_MAGICK_ERROR();
964     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
965     return -1;
966   }
967   
968   if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL) {
969     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
970     return -1;
971   }
972   
973   r->content_type = apr_psprintf(r->pool, "image/png");
974   ap_set_content_type(r, "image/png");
975   DBG(r, "REQ[%X] convert to png", TO_ADDR(r));
976   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
977   return 0;
978 }
979
980
981 static int
982 s_convert_to_gif(MagickWand *magick_wand, request_rec *r, device_table *spec)
983 {
984   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
985   if (MagickSetImageCompression(magick_wand,LZWCompression) == MagickFalse) {
986     EXIT_MAGICK_ERROR();
987     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
988     return -1;
989   }
990   
991   if (MagickSetImageFormat(magick_wand, "gif") == MagickFalse) {
992     EXIT_MAGICK_ERROR();
993     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
994     return -1;
995   }
996   
997   if (MagickStripImage(magick_wand) == MagickFalse) {
998     EXIT_MAGICK_ERROR();
999     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1000     return -1;
1001   }
1002   
1003   if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL) {
1004     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1005     return -1;
1006   }
1007   
1008   r->content_type = apr_psprintf(r->pool, "image/gif");
1009   ap_set_content_type(r, "image/gif");
1010   
1011   DBG(r,"REQ[%X] convert to gif",TO_ADDR(r));
1012   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1013   return 0;
1014 }
1015
1016
1017 static int
1018 s_convert_to_bmp(MagickWand *magick_wand, request_rec *r, device_table *spec)
1019 {
1020   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
1021   if (MagickSetImageCompression(magick_wand,NoCompression) == MagickFalse) {
1022     EXIT_MAGICK_ERROR();
1023     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1024     return -1;
1025   }
1026   
1027   if (MagickSetImageFormat(magick_wand, "bmp") == MagickFalse) {
1028     EXIT_MAGICK_ERROR();
1029     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1030     return -1;
1031   }
1032   
1033   if (MagickStripImage(magick_wand) == MagickFalse) {
1034     EXIT_MAGICK_ERROR();
1035     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1036     return -1;
1037   }
1038   
1039   if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL) {
1040     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1041     return -1;
1042   }
1043   
1044   r->content_type = apr_psprintf(r->pool, "image/bmp");
1045   ap_set_content_type(r, "image/bmp");
1046   
1047   DBG(r,"REQ[%X] convert to bmp(unsupported)", TO_ADDR(r));
1048   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1049   return 0;
1050 }
1051
1052
1053 static char *
1054 s_create_blob_data(request_rec          *r, 
1055                    device_table         *spec, 
1056                    query_string_param_t *qsp,
1057                    char                 *indata,
1058                    apr_size_t           *len)
1059 {
1060   apr_size_t         writebyte;
1061   unsigned short     crc;
1062   img_conv_mode_t    mode = qsp->mode;
1063
1064   char *writedata = NULL;
1065   char *dst       = NULL;
1066   MagickWand *magick_wand;
1067
1068   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
1069
1070   magick_wand = NewMagickWand();
1071
1072   if (MagickReadImageBlob(magick_wand,indata, *len) == MagickFalse) {
1073     EXIT_MAGICK_ERROR();
1074     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1075     return NULL;
1076   }
1077
1078   if (MagickStripImage(magick_wand) == MagickFalse) {
1079     ERR(r, "REQ[%X] mod_chxj: strip image failure.",TO_ADDR(r));
1080     EXIT_MAGICK_ERROR();
1081     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1082     return NULL;
1083   }
1084
1085   {
1086     int oldw = MagickGetImageWidth(magick_wand);
1087     int oldh = MagickGetImageHeight(magick_wand);
1088     int done_fixup_size = 0;
1089     if ((qsp->mode == IMG_CONV_MODE_WALLPAPER && spec->wp_width < oldw && spec->wp_heigh < oldh)
1090       || (qsp->mode != IMG_CONV_MODE_WALLPAPER && spec->width < oldw && spec->heigh < oldh)) {
1091       /*
1092        * The size of the image is changed.
1093        */
1094       DBG(r,"REQ[%X] call s_fixup_size()",TO_ADDR(r));
1095
1096       if ((magick_wand = s_fixup_size(magick_wand, r, spec, qsp)) == NULL) {
1097         EXIT_MAGICK_ERROR();
1098         DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1099         return NULL;
1100       }
1101
1102       done_fixup_size = 1;
1103     }
1104     /*
1105      * The colors of the image is changed.
1106      */
1107     DBG(r,"REQ[%X] call s_fixup_color()",TO_ADDR(r));
1108
1109     if ((magick_wand = s_fixup_color(magick_wand, r,spec, mode)) == NULL) {
1110       EXIT_MAGICK_ERROR();
1111       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1112       return NULL;
1113     }
1114
1115     /*
1116      * DEPTH of the image is changed.
1117      */
1118     DBG(r,"REQ[%X] call s_fixup_depth()",TO_ADDR(r));
1119
1120     if ((magick_wand = s_fixup_depth(magick_wand, r, spec)) == NULL) {
1121       EXIT_MAGICK_ERROR();
1122       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1123       return NULL;
1124     }
1125
1126
1127     if (! done_fixup_size) {
1128       /*
1129        * The size of the image is changed.
1130        */
1131       DBG(r,"REQ[%X] call s_fixup_size()",TO_ADDR(r));
1132       if ((magick_wand = s_fixup_size(magick_wand, r, spec, qsp)) == NULL) {
1133         EXIT_MAGICK_ERROR();
1134         DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1135         return NULL;
1136       }
1137     }
1138   }
1139
1140   char *nowFormat = MagickGetImageFormat(magick_wand);
1141   int fixFormatFlag = 0;
1142   if (nowFormat) {
1143     if (STRCASEEQ('g','G',"gif",nowFormat)) {
1144       if (spec->available_gif) {
1145         if (s_convert_to_gif(magick_wand, r, spec)) {
1146           DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1147           return NULL;
1148         }
1149         fixFormatFlag = 1;
1150       }
1151     }
1152     else if (STRCASEEQ('j','J',"jpg",nowFormat)||STRCASEEQ('j','J',"jpeg",nowFormat)) {
1153       if (spec->available_jpeg) {
1154         if (s_convert_to_jpeg(magick_wand, r, spec)) {
1155           DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1156           return NULL;
1157         }
1158         fixFormatFlag = 1;
1159       }
1160     }
1161     else if (STRCASEEQ('p','P',"png",nowFormat)) {
1162       if (spec->available_png) {
1163         if (s_convert_to_png(magick_wand, r, spec)) {
1164           DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1165           return NULL;
1166         }
1167         fixFormatFlag = 1;
1168       }
1169     }
1170   }
1171
1172   DBG(r,"REQ[%X] start convert and compression", TO_ADDR(r));
1173
1174   if (!fixFormatFlag) {
1175     if (spec->available_jpeg) {
1176       if (s_convert_to_jpeg(magick_wand, r, spec)) {
1177         DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1178         return NULL;
1179       }
1180     }
1181     else if (spec->available_png) {
1182       if (s_convert_to_png(magick_wand, r, spec)) {
1183         DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1184         return NULL;
1185       }
1186     }
1187     else if (spec->available_gif) {
1188       if (s_convert_to_gif(magick_wand, r, spec)) {
1189         DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1190         return NULL;
1191       }
1192     }
1193     else if (spec->available_bmp2 || spec->available_bmp4) {
1194       if (s_convert_to_bmp(magick_wand, r, spec)) {
1195         DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1196         return NULL;
1197       }
1198     }
1199   }
1200   /*--------------------------------------------------------------------------*/
1201   /* Add Comment (Copyright and so on.)                                       */
1202   /*--------------------------------------------------------------------------*/
1203   DBG(r,"REQ[%X] call s_add_copyright()",TO_ADDR(r));
1204
1205   if ((magick_wand = s_add_copyright(magick_wand, r, spec)) == NULL) {
1206     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1207     return NULL;
1208   }
1209
1210   writedata = (char*)MagickGetImageBlob(magick_wand, &writebyte);
1211
1212   if (! writebyte) {
1213     DestroyMagickWand(magick_wand);
1214     ERR(r,"REQ[%X] %s:%d convert failure to Jpeg ",TO_ADDR(r),__FILE__,__LINE__);
1215     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1216     return NULL;
1217   }
1218
1219   DBG(r,"REQ[%X] end convert and compression", TO_ADDR(r));
1220
1221
1222   
1223   dst = apr_palloc(r->pool, writebyte+2);
1224
1225   memcpy(dst, writedata, writebyte);
1226   /*--------------------------------------------------------------------------*/
1227   /* CRC is added for AU for EzGET.                                           */
1228   /*--------------------------------------------------------------------------*/
1229   if (spec->html_spec_type == CHXJ_SPEC_XHtml_Mobile_1_0
1230   ||  spec->html_spec_type == CHXJ_SPEC_Hdml) {
1231     crc = s_add_crc(writedata, writebyte);
1232     dst[writebyte + 0] = (crc >> 8) & 0xff;
1233     dst[writebyte + 1] = (crc     ) & 0xff;
1234     writebyte += 2;
1235   }
1236
1237   DestroyMagickWand(magick_wand);
1238
1239   *len = writebyte;
1240   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1241   return dst;
1242 }
1243
1244
1245 static MagickWand *
1246 s_fixup_size(MagickWand           *magick_wand, 
1247              request_rec          *r, 
1248              device_table         *spec, 
1249              query_string_param_t *qsp)
1250 {
1251   img_conv_mode_t mode = qsp->mode;
1252   int oldw;
1253   int oldh;
1254   int neww;
1255   int newh;
1256   int c_width;
1257   int c_heigh;
1258
1259   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
1260   oldw = MagickGetImageWidth(magick_wand);
1261   oldh = MagickGetImageHeight(magick_wand);
1262
1263   DBG(r,"REQ[%X] detect width=[%d]", TO_ADDR(r),oldw);
1264   DBG(r,"REQ[%X] detect heigh=[%d]", TO_ADDR(r),oldh);
1265
1266   neww = oldw;
1267   newh = oldh;
1268
1269   DBG(r,"REQ[%X] detect spec width=[%d]", TO_ADDR(r),spec->width);
1270   DBG(r,"REQ[%X] detect spec heigh=[%d]", TO_ADDR(r),spec->heigh);
1271
1272   c_width = spec->width;
1273   c_heigh = spec->heigh;
1274
1275   switch(mode) {
1276   case IMG_CONV_MODE_THUMBNAIL:
1277
1278     DBG(r,"REQ[%X] **** detect thumbnail mode ****",TO_ADDR(r));
1279
1280     if (neww > c_width) {
1281       newh = (int)((double)newh * (double)((double)c_width / (double)neww));
1282       neww = (int)((double)neww * (double)((double)c_width / (double)neww));
1283     }
1284     if (newh > c_heigh) {
1285       neww = (int)((double)neww * (double)((double)c_heigh / (double)newh));
1286       newh = (int)((double)newh * (double)((double)c_heigh / (double)newh));
1287     }
1288
1289     neww = (int)((double)(neww / 3) * 0.8);
1290     newh = (int)((double)(newh / 3) * 0.8);
1291     break;
1292
1293   case IMG_CONV_MODE_WALLPAPER:
1294   case IMG_CONV_MODE_EZGET:
1295
1296     DBG(r,"REQ[%X] **** detect wallpaper mode ****", TO_ADDR(r));
1297
1298     if (spec->wp_width && spec->wp_heigh) {
1299       c_width = spec->wp_width;
1300       c_heigh = spec->wp_heigh;
1301     }
1302
1303     DBG(r,"REQ[%X] calc new width and height", TO_ADDR(r));
1304
1305     neww = (int)((double)neww * (double)((double)c_heigh / (double)newh));
1306     newh = (int)((double)newh * (double)((double)c_heigh / (double)newh));
1307
1308     DBG(r,"REQ[%X] newh = [%d] neww = [%d]", TO_ADDR(r),newh, neww);
1309     break;
1310
1311   default:
1312
1313     DBG(r,"REQ[%X] **** detect normal mode ****", TO_ADDR(r));
1314
1315     if (qsp->ua_flag != UA_IGN && spec->html_spec_type != CHXJ_SPEC_UNKNOWN) {
1316       if (neww > c_width) {
1317         newh = (int)((double)newh * (double)((double)c_width / (double)neww));
1318         neww = (int)((double)neww * (double)((double)c_width / (double)neww));
1319       }
1320
1321       if (newh > c_heigh) {
1322         neww = (int)((double)neww * (double)((double)c_heigh / (double)newh));
1323         newh = (int)((double)newh * (double)((double)c_heigh / (double)newh));
1324       }
1325     }
1326     break;
1327   }
1328
1329   if (neww == 0) neww = 1;
1330   if (newh == 0) newh = 1;
1331
1332   if (spec->html_spec_type != CHXJ_SPEC_UNKNOWN) {
1333     DBG(r,"REQ[%X] convert width=[%d --> %d]", TO_ADDR(r),oldw, neww);
1334     DBG(r,"REQ[%X] convert heigh=[%d --> %d]", TO_ADDR(r),oldh, newh);
1335   
1336     MagickResetIterator(magick_wand);
1337   
1338     while (MagickNextImage(magick_wand) != MagickFalse) {
1339       switch (mode) {
1340       case IMG_CONV_MODE_WALLPAPER:
1341       case IMG_CONV_MODE_EZGET:
1342   
1343         if (MagickResizeImage(magick_wand,neww,newh,LanczosFilter,1.0) == MagickFalse) {
1344           EXIT_MAGICK_ERROR();
1345           DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1346           return NULL;
1347         }
1348   
1349         if (MagickCropImage(magick_wand, 
1350                         (unsigned long)c_width, 
1351                         (unsigned long)c_heigh,
1352                         (long)((neww - c_width) / 2),
1353                         (long)((newh - c_heigh) / 2)) == MagickFalse) {
1354           EXIT_MAGICK_ERROR();
1355           DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1356           return NULL;
1357         }
1358         break;
1359   
1360       case IMG_CONV_MODE_NORMAL:
1361         if (qsp->width) {
1362           DBG(r,"REQ[%X] convert width=[%d --> %d]", TO_ADDR(r),neww, qsp->width);
1363           neww = qsp->width;
1364         }
1365         if (qsp->height) {
1366           DBG(r,"REQ[%X] convert heigh=[%d --> %d]", TO_ADDR(r),newh, qsp->height);
1367           newh = qsp->height;
1368         }
1369   
1370       default:
1371         if (MagickResizeImage(magick_wand,neww,newh,LanczosFilter,1.0) == MagickFalse) {
1372           EXIT_MAGICK_ERROR();
1373           DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1374           return NULL;
1375         }
1376         break;
1377       }
1378   
1379       if (spec->html_spec_type != CHXJ_SPEC_UNKNOWN) {
1380         if (MagickSetImageUnits(magick_wand, PixelsPerInchResolution) == MagickFalse) {
1381           EXIT_MAGICK_ERROR();
1382           DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1383           return NULL;
1384         }
1385     
1386         if (MagickSetImageResolution(magick_wand,
1387                                      (double)spec->dpi_width,
1388                                      (double)spec->dpi_heigh) == MagickFalse) {
1389           EXIT_MAGICK_ERROR();
1390           DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1391           return NULL;
1392         }
1393     
1394         if (MagickSetImageDispose(magick_wand, BackgroundDispose) == MagickFalse) {
1395           EXIT_MAGICK_ERROR();
1396           DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1397           return NULL;
1398         }
1399       }
1400     }
1401   }
1402   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1403   return magick_wand;
1404 }
1405
1406
1407 static MagickWand *
1408 s_fixup_color(MagickWand *magick_wand, request_rec *r, device_table *spec, img_conv_mode_t UNUSED(mode))
1409 {
1410   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
1411
1412   if (spec->html_spec_type == CHXJ_SPEC_UNKNOWN) {
1413     DBG(r, "REQ[%X] Pass s_fixup_color proc", TO_ADDR(r));
1414     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1415     return magick_wand;
1416   }
1417
1418   unsigned long colors = MagickGetImageColors(magick_wand);
1419   DBG(r, "REQ[%X] now color:[%ld] spec->color:[%ld]",TO_ADDR(r), colors, (unsigned long)spec->color);
1420   if (colors < (unsigned long)spec->color) {
1421     DBG(r, "REQ[%X] Pass s_fixup_color proc. color:[%ld] spec->color:[%d]", TO_ADDR(r),colors, spec->color);
1422     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1423     return magick_wand;
1424   }
1425
1426   if (spec->color >= 256) {
1427
1428     DBG(r,"REQ[%X] call MagickQuantizeImage() spec->color=[%d]",TO_ADDR(r),spec->color);
1429
1430     if (MagickQuantizeImage(magick_wand,
1431                            spec->color,
1432                            RGBColorspace,
1433                            0,
1434                            1,
1435                            0) == MagickFalse) {
1436       EXIT_MAGICK_ERROR();
1437       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1438       return NULL;
1439     }
1440
1441     DBG(r,"REQ[%X] call end MagickQuantizeImage() spec->color=[%d]",TO_ADDR(r),spec->color);
1442
1443   }
1444   else {
1445     DBG(r,"REQ[%X] call MagickQuantizeImage() spec->color=[%d]",TO_ADDR(r),spec->color);
1446
1447     if (MagickQuantizeImage(magick_wand,
1448                            spec->color,
1449                            GRAYColorspace,
1450                            0,
1451                            1,
1452                            0) == MagickFalse) {
1453       EXIT_MAGICK_ERROR();
1454       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1455       return NULL;
1456     }
1457
1458     DBG(r,"REQ[%X] call end MagickQuantizeImage() spec->color=[%d]",TO_ADDR(r),spec->color);
1459   }
1460
1461
1462   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1463
1464   return magick_wand;
1465 }
1466
1467
1468
1469 static MagickWand *
1470 s_fixup_depth(MagickWand *magick_wand, request_rec *r, device_table *spec)
1471 {
1472   if (spec->html_spec_type == CHXJ_SPEC_UNKNOWN) {
1473     DBG(r, "Pass s_fixup_depth proc");
1474     return magick_wand;
1475   }
1476
1477   if (spec->color == 15680000) {
1478     if (MagickSetImageDepth(magick_wand, 24) == MagickFalse) {
1479       EXIT_MAGICK_ERROR();
1480       return NULL;
1481     }
1482   }
1483   else 
1484   if (spec->color == 262144) {
1485     if (MagickSetImageDepth(magick_wand, 18) == MagickFalse) {
1486       EXIT_MAGICK_ERROR();
1487       return NULL;
1488     }
1489   }
1490   else
1491   if (spec->color == 65536) {
1492     if (MagickSetImageDepth(magick_wand, 16) == MagickFalse) {
1493       EXIT_MAGICK_ERROR();
1494       return NULL;
1495     }
1496   }
1497   else
1498   if (spec->color == 4096) {
1499     if (MagickSetImageDepth(magick_wand, 12) == MagickFalse) {
1500       EXIT_MAGICK_ERROR();
1501       return NULL;
1502     }
1503   }
1504   else
1505   if (spec->color == 256) {
1506     if (MagickSetImageDepth(magick_wand, 8) == MagickFalse) {
1507       EXIT_MAGICK_ERROR();
1508       return NULL;
1509     }
1510   }
1511   else
1512   if (spec->color == 4) {
1513     if (MagickSetImageDepth(magick_wand, 2) == MagickFalse) {
1514       EXIT_MAGICK_ERROR();
1515       return NULL;
1516     }
1517   }
1518   else
1519   if (spec->color == 2) {
1520     if (MagickSetImageDepth(magick_wand, 1) == MagickFalse) {
1521       EXIT_MAGICK_ERROR();
1522       return NULL;
1523     }
1524   }
1525
1526   return magick_wand;
1527 }
1528
1529
1530 static MagickWand *
1531 s_add_copyright(MagickWand *magick_wand, request_rec *r, device_table *spec)
1532 {
1533   mod_chxj_config *conf = chxj_get_module_config(r->per_dir_config, &chxj_module);
1534
1535   if (spec->html_spec_type == CHXJ_SPEC_UNKNOWN) {
1536     DBG(r, "REQ[%X] Pass add_copiright proc", TO_ADDR(r));
1537     return magick_wand;
1538   }
1539
1540   if (conf->image_copyright) {
1541
1542     DBG(r, "REQ[%X] Add COPYRIGHT [%s]", TO_ADDR(r),conf->image_copyright);
1543
1544     if (spec->html_spec_type == CHXJ_SPEC_Jhtml
1545     ||  spec->html_spec_type == CHXJ_SPEC_Jxhtml) {
1546       apr_table_setn(r->headers_out, "x-jphone-copyright", "no-transfer");
1547       if (MagickCommentImage(magick_wand, 
1548                              apr_psprintf(r->pool, 
1549                                           "Copyright(C) %s", 
1550                                           conf->image_copyright)) == MagickFalse) 
1551         goto on_error;
1552     }
1553     else
1554     if (spec->html_spec_type == CHXJ_SPEC_XHtml_Mobile_1_0
1555     ||  spec->html_spec_type == CHXJ_SPEC_Hdml) {
1556       if (MagickCommentImage(magick_wand, 
1557                              apr_psprintf(r->pool, 
1558                                          "kddi_copyright=on,%s", 
1559                                           conf->image_copyright)) == MagickFalse) 
1560         goto on_error;
1561     }
1562     else {
1563       if (MagickCommentImage(magick_wand, 
1564                             apr_psprintf(r->pool, 
1565                                          "copy=\"NO\",%s",
1566                                          conf->image_copyright)) == MagickFalse)
1567         goto on_error;
1568     }
1569   }
1570   else {
1571     if (MagickCommentImage(magick_wand, "mod_chxj") == MagickFalse)
1572       goto on_error;
1573   }
1574   return magick_wand;
1575
1576 on_error:
1577   EXIT_MAGICK_ERROR();
1578   return NULL;
1579 }
1580
1581 static MagickWand *
1582 s_img_down_sizing(MagickWand *magick_wand, request_rec *r, device_table *spec)
1583 {
1584   MagickBooleanType  status;
1585   unsigned long      quality = 70;
1586   apr_size_t         writebyte = 0;
1587   char               *writedata;
1588   apr_size_t         prev_size = 0;
1589   char               *fmt;
1590   int                fmt_type = 0;
1591   
1592   writedata = (char *)MagickGetImageBlob(magick_wand, &writebyte);
1593   prev_size = writebyte;
1594
1595   
1596   fmt = MagickGetImageFormat(magick_wand);
1597   if (fmt) {
1598     if (STRCASEEQ('j','J',"jpg",fmt)) fmt_type = 1;
1599     if (STRCASEEQ('p','P',"png",fmt)) fmt_type = 2;
1600     if (STRCASEEQ('g','G',"gif",fmt)) fmt_type = 3;
1601     if (STRCASEEQ('b','B',"bmp",fmt)) fmt_type = 4;
1602   }
1603   if (fmt_type == 1) {
1604     do {
1605       if (MagickSetImageCompressionQuality(magick_wand, quality) == MagickFalse) {
1606         EXIT_MAGICK_ERROR();
1607         return NULL;
1608       }
1609   
1610       writedata = (char*)MagickGetImageBlob(magick_wand, &writebyte);
1611       if (writebyte >= prev_size) {
1612         DBG(r, "REQ[%X] quality=[%ld] size=[%d]", TO_ADDR(r),(long)quality, (int)writebyte);
1613         quality += 5;
1614         if (quality > 100) {
1615           if (MagickSetImageCompression(magick_wand,NoCompression) == MagickFalse) {
1616             EXIT_MAGICK_ERROR();
1617             return NULL;
1618           }
1619           break;
1620         }
1621         if (MagickSetImageCompressionQuality(magick_wand, quality) == MagickFalse) {
1622           EXIT_MAGICK_ERROR();
1623           return NULL;
1624         }
1625         break;
1626       }
1627   
1628       DBG(r, "REQ[%X] quality=[%ld] size=[%d]", TO_ADDR(r),(long)quality, (int)writebyte);
1629   
1630       if (spec->cache == 0)
1631         break;
1632   
1633       if (writebyte <= (unsigned int)spec->cache)
1634         break;
1635   
1636       quality -= 5;
1637   
1638       if (quality == 0 || quality > 100)
1639         break;
1640   
1641     }
1642     while (1);
1643   }
1644
1645
1646   if (spec->cache > 0 
1647   &&  writebyte   > (unsigned int)spec->cache) {
1648     unsigned long now_color = spec->color;
1649     unsigned long depth     = 0;
1650     do {
1651       switch(now_color) {
1652       case 2:      depth = 1; break;
1653       case 4:      now_color = 2;        depth = 1;  break;
1654       case 8:      now_color = 4;        depth = 2;  break;
1655       case 16:     now_color = 8;        depth = 3;  break;
1656       case 256:    now_color = 16;       depth = 4;  break;
1657       case 4096:   now_color = 256;      depth = 8;  break;
1658       case 65536:  now_color = 4096;     depth = 12; break;
1659       case 262144: now_color = 65536;    depth = 16; break;
1660       case 15680000: now_color = 262144; depth = 18; break;
1661       default:
1662         now_color = 2;
1663         break;
1664       }
1665
1666       if (now_color <= 2) break;
1667
1668
1669       if (now_color >= 8) {
1670         status = MagickQuantizeImage(magick_wand,
1671                              now_color,
1672                              RGBColorspace,
1673                              0,
1674                              1,
1675                              0);
1676       }
1677       else {
1678         status = MagickQuantizeImage(magick_wand,
1679                              now_color,
1680                              GRAYColorspace,
1681                              0,
1682                              1,
1683                              0);
1684         MagickSetImageType(magick_wand, GrayscaleType);
1685       }
1686       if (status == MagickFalse) {
1687         EXIT_MAGICK_ERROR();
1688         return NULL;
1689       }
1690       if (fmt_type != 2) {
1691         if (MagickSetImageDepth(magick_wand, depth) == MagickFalse) {
1692           EXIT_MAGICK_ERROR();
1693           return NULL;
1694         }
1695       }
1696       writedata = (char*)MagickGetImageBlob(magick_wand, &writebyte);
1697
1698       DBG(r,"REQ[%X] now_color=[%ld] size=[%d]", TO_ADDR(r),(long)now_color, (int)writebyte);
1699
1700       /* Once per request */
1701       break;
1702     }
1703     while(now_color > 2);
1704   }
1705
1706   return magick_wand;
1707 }
1708
1709
1710 static apr_status_t 
1711 s_send_cache_file(
1712   mod_chxj_config      *conf, 
1713   device_table         *spec,
1714   query_string_param_t *query_string, 
1715   request_rec          *r, 
1716   const char           *tmpfile)
1717 {
1718   apr_status_t rv;
1719   apr_finfo_t  st;
1720   apr_file_t   *fout;
1721   apr_size_t   sendbyte;
1722   char         *contentLength;
1723
1724   rv = apr_stat(&st, tmpfile, APR_FINFO_MIN, r->pool);
1725   if (rv != APR_SUCCESS)
1726     return HTTP_NOT_FOUND;
1727
1728
1729   DBG(r, "REQ[%X] mode:[%d]",    TO_ADDR(r), query_string->mode);
1730   DBG(r, "REQ[%X] name:[%s]",    TO_ADDR(r), query_string->name);
1731   DBG(r, "REQ[%X] offset:[%ld]", TO_ADDR(r), query_string->offset);
1732   DBG(r, "REQ[%X] count:[%ld]",  TO_ADDR(r), query_string->count);
1733
1734   /* for mod_cache */
1735   {
1736     apr_table_setn(r->headers_out, "Vary", "User-Agent");
1737     apr_table_setn(r->err_headers_out, "Vary", "User-Agent");
1738     ap_update_mtime(r, st.mtime);
1739     ap_set_last_modified(r);
1740   }
1741
1742   if (query_string->mode != IMG_CONV_MODE_EZGET && query_string->name == NULL) {
1743     contentLength = apr_psprintf(r->pool, "%d", (int)st.size);
1744     apr_table_setn(r->headers_out, "Content-Length", (const char*)contentLength);
1745   
1746     DBG(r,"REQ[%X] Content-Length:[%d]", TO_ADDR(r),(int)st.size);
1747     MagickWand *magick_wand = NewMagickWand();
1748     if (MagickReadImage(magick_wand,tmpfile) == MagickFalse) {
1749       EXIT_MAGICK_ERROR();
1750       return HTTP_NOT_FOUND;
1751     }
1752     if (MagickStripImage(magick_wand) == MagickFalse) {
1753       ERR(r, "mod_chxj: strip image failure.");
1754       EXIT_MAGICK_ERROR();
1755       return HTTP_NOT_FOUND;
1756     }
1757     char *nowFormat = MagickGetImageFormat(magick_wand);
1758     DestroyMagickWand(magick_wand);
1759     if (nowFormat) {
1760       if (STRCASEEQ('j','J',"jpeg",nowFormat) || STRCASEEQ('j','J',"jpg",nowFormat)) {
1761         DBG(r, "REQ[%X] detect cache file => jpg.",TO_ADDR(r));
1762         ap_set_content_type(r, "image/jpeg");
1763       }
1764       else if (STRCASEEQ('p','P',"png", nowFormat)) {
1765         DBG(r, "REQ[%X] detect cache file => png.", TO_ADDR(r));
1766         ap_set_content_type(r, "image/png");
1767       }
1768       else if (STRCASEEQ('g','G',"gif", nowFormat)) {
1769         DBG(r, "REQ[%X] detect cache file => gif.",TO_ADDR(r));
1770         ap_set_content_type(r, "image/gif");
1771       }
1772       else if (STRCASEEQ('b','B',"bmp", nowFormat)) {
1773         DBG(r, "REQ[%X] detect cache file => bmp.",TO_ADDR(r));
1774         ap_set_content_type(r, "image/bmp");
1775       }
1776       else {
1777         ERR(r, "detect unknown file");
1778         return HTTP_NOT_FOUND;
1779       }
1780     }
1781     if (conf->image_copyright) {
1782       DBG(r, "REQ[%X] Add COPYRIGHT Header for SoftBank [%s]", TO_ADDR(r), conf->image_copyright);
1783       if (spec->html_spec_type == CHXJ_SPEC_Jhtml ||  spec->html_spec_type == CHXJ_SPEC_Jxhtml) {
1784         apr_table_setn(r->headers_out, "x-jphone-copyright", "no-transfer");
1785       }
1786     }
1787     rv = apr_file_open(&fout, tmpfile, 
1788       APR_FOPEN_READ | APR_FOPEN_BINARY | APR_FOPEN_BUFFERED | APR_FOPEN_SHARELOCK | APR_FOPEN_SENDFILE_ENABLED, 
1789       APR_OS_DEFAULT, r->pool);
1790     if (rv != APR_SUCCESS) {
1791       ERR(r, "REQ[%X] %s:%d cache file open failed[%s]", TO_ADDR(r),__FILE__,__LINE__,tmpfile);
1792       return HTTP_NOT_FOUND;
1793     }
1794     ap_send_fd(fout, r, 0, st.size, &sendbyte);
1795     apr_file_close(fout);
1796     ap_rflush(r);
1797     DBG(r, "REQ[%X] send file data[%d]byte", TO_ADDR(r), (int)sendbyte);
1798   }
1799   else
1800   if (query_string->mode == IMG_CONV_MODE_EZGET) {
1801     char *name = apr_pstrdup(r->pool, basename(r->filename));
1802     name[strlen(name)-4] = 0;
1803     if (strcasecmp(r->content_type, "image/jpeg") == 0) {
1804
1805       chxj_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
1806       ap_rprintf(r, HDML_FIRST_PAGE, r->uri, name, ".jpg", (long)st.size, "devjaww", name);
1807     }
1808     else
1809     if (strcasecmp(r->content_type, "image/bmp") == 0) {
1810       chxj_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
1811       ap_rprintf(r, HDML_FIRST_PAGE, r->uri, name, ".bmp", (long)st.size, "devabm", name);
1812     }
1813     else
1814     if (strcasecmp(r->content_type, "image/png") == 0) {
1815       chxj_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
1816       ap_rprintf(r, HDML_FIRST_PAGE, r->uri, name, ".png", (long)st.size, "dev8aww", name);
1817     }
1818     else
1819     if (strcasecmp(r->content_type, "image/gif") == 0) {
1820       chxj_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
1821       ap_rprintf(r, HDML_FIRST_PAGE, r->uri, name, ".gif", (long)st.size, "devgi0z", name);
1822     }
1823   }
1824   else
1825   if (query_string->mode == IMG_CONV_MODE_WALLPAPER && query_string->name != NULL) {
1826     if (query_string->count == -1 && query_string->offset == -1) {
1827       chxj_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
1828       ap_rprintf(r, HDML_SUCCESS_PAGE);
1829       ap_rflush(r);
1830     }
1831     else
1832     if (query_string->count == -2 && query_string->offset == -1) {
1833       chxj_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
1834       ap_rprintf(r, HDML_FAIL_PAGE);
1835       ap_rflush(r);
1836     }
1837     else { 
1838       chxj_set_content_type(r, "application/x-up-download");
1839       contentLength = apr_psprintf(r->pool, "%ld", query_string->count);
1840       apr_table_setn(r->headers_out, "Content-Length", (const char*)contentLength);
1841   
1842       DBG(r, "REQ[%X] Content-Length:[%d]", TO_ADDR(r),(int)st.size);
1843
1844       rv = apr_file_open(&fout, tmpfile, 
1845         APR_FOPEN_READ | APR_FOPEN_BINARY | APR_FOPEN_BUFFERED | APR_FOPEN_SHARELOCK | APR_FOPEN_SENDFILE_ENABLED, 
1846         APR_OS_DEFAULT, r->pool);
1847
1848       if (rv != APR_SUCCESS) {
1849         ERR(r,"REQ[%X] %s:%d tmpfile open failed[%s]", TO_ADDR(r),__FILE__,__LINE__,tmpfile);
1850         return HTTP_NOT_FOUND;
1851       }
1852
1853       ap_send_fd(fout, r, query_string->offset, query_string->count, &sendbyte);
1854       apr_file_close(fout);
1855       ap_rflush(r);
1856       DBG(r, "REQ[%X] send file data[%d]byte", TO_ADDR(r),(int)sendbyte);
1857     }
1858   }
1859   
1860   return OK;
1861 }
1862
1863
1864 static apr_status_t 
1865 s_send_original_file(request_rec *r, const char *originalfile)
1866 {
1867   apr_status_t rv;
1868   apr_finfo_t  st;
1869   apr_file_t   *fout;
1870   apr_size_t   sendbyte = 0;
1871
1872   rv = apr_stat(&st, originalfile, APR_FINFO_MIN, r->pool);
1873   if (rv != APR_SUCCESS)
1874     return HTTP_NOT_FOUND;
1875
1876   /* for With mod_cache */
1877   {
1878     apr_table_setn(r->headers_out, "Vary", "User-Agent");
1879     apr_table_setn(r->err_headers_out, "Vary", "User-Agent");
1880     ap_update_mtime(r, st.mtime);
1881     ap_set_last_modified(r);
1882   }
1883
1884   rv = apr_file_open(&fout, originalfile, 
1885     APR_FOPEN_READ | APR_FOPEN_BINARY | APR_FOPEN_BUFFERED | APR_FOPEN_SHARELOCK | APR_FOPEN_SENDFILE_ENABLED, 
1886     APR_OS_DEFAULT, r->pool);
1887   if (rv != APR_SUCCESS) {
1888     DBG(r, "REQ[%X] originalfile open failed[%s]", TO_ADDR(r),originalfile);
1889     return HTTP_NOT_FOUND;
1890   }
1891
1892   ap_send_fd(fout, r, 0, st.size, &sendbyte);
1893   apr_file_close(fout);
1894   ap_rflush(r);
1895   DBG(r, "REQ[%X] send file data[%d]byte", TO_ADDR(r),(int)sendbyte);
1896   
1897   return OK;
1898 }
1899
1900
1901 static apr_status_t 
1902 s_header_only_cache_file(device_table *spec, query_string_param_t *query_string, request_rec *r, const char *tmpfile)
1903 {
1904   apr_status_t rv;
1905   apr_finfo_t  st;
1906   char         *contentLength;
1907   mod_chxj_config *conf = ap_get_module_config(r->per_dir_config, &chxj_module);
1908
1909   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
1910
1911   rv = apr_stat(&st, tmpfile, APR_FINFO_MIN, r->pool);
1912   if (rv != APR_SUCCESS) {
1913     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1914     return HTTP_NOT_FOUND;
1915   }
1916
1917   DBG(r, "REQ[%X] mode:[%d]",    TO_ADDR(r), query_string->mode);
1918   DBG(r, "REQ[%X] name:[%s]",    TO_ADDR(r), query_string->name);
1919   DBG(r, "REQ[%X] offset:[%ld]", TO_ADDR(r), query_string->offset);
1920   DBG(r, "REQ[%X] count:[%ld]",  TO_ADDR(r), query_string->count);
1921
1922   if (query_string->mode != IMG_CONV_MODE_EZGET && query_string->name == NULL) {
1923     contentLength = apr_psprintf(r->pool, "%d", (int)st.size);
1924     apr_table_setn(r->headers_out, "Content-Length", (const char*)contentLength);
1925
1926     MagickWand *magick_wand = NewMagickWand();
1927     if (MagickReadImage(magick_wand,tmpfile) == MagickFalse) {
1928       EXIT_MAGICK_ERROR();
1929       return HTTP_NOT_FOUND;
1930     }
1931     if (MagickStripImage(magick_wand) == MagickFalse) {
1932       ERR(r, "mod_chxj: strip image failure.");
1933       EXIT_MAGICK_ERROR();
1934       return HTTP_NOT_FOUND;
1935     }
1936     char *nowFormat = MagickGetImageFormat(magick_wand);
1937     DestroyMagickWand(magick_wand);
1938     if (nowFormat) {
1939       if (STRCASEEQ('j','J',"jpeg",nowFormat) || STRCASEEQ('j','J',"jpg",nowFormat)) {
1940         DBG(r, "REQ[%X] detect cache file => jpg.",TO_ADDR(r));
1941         ap_set_content_type(r, "image/jpeg");
1942       }
1943       else if (STRCASEEQ('p','P',"png", nowFormat)) {
1944         DBG(r, "REQ[%X] detect cache file => png.",TO_ADDR(r));
1945         ap_set_content_type(r, "image/png");
1946       }
1947       else if (STRCASEEQ('g','G',"gif", nowFormat)) {
1948         DBG(r, "REQ[%X] detect cache file => gif.",TO_ADDR(r));
1949         ap_set_content_type(r, "image/gif");
1950       }
1951       else if (STRCASEEQ('b','B',"bmp", nowFormat)) {
1952         DBG(r, "REQ[%X] detect cache file => bmp.",TO_ADDR(r));
1953         ap_set_content_type(r, "image/bmp");
1954       }
1955       else {
1956         ERR(r, "REQ[%X] detect unknown file", TO_ADDR(r));
1957         return HTTP_NOT_FOUND;
1958       }
1959     }
1960   
1961     DBG(r,"REQ[%X] Content-Length:[%d]", TO_ADDR(r),(int)st.size);
1962   }
1963   else
1964   if (query_string->mode == IMG_CONV_MODE_EZGET) {
1965     char *name = apr_pstrdup(r->pool, basename(r->filename));
1966     name[strlen(name)-4] = 0;
1967     if (strcasecmp(r->content_type, "image/jpeg") == 0) {
1968
1969       chxj_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
1970     }
1971     else
1972     if (strcasecmp(r->content_type, "image/bmp") == 0) {
1973       chxj_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
1974     }
1975     else
1976     if (strcasecmp(r->content_type, "image/png") == 0) {
1977       chxj_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
1978     }
1979     else
1980     if (strcasecmp(r->content_type, "image/gif") == 0) {
1981       chxj_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
1982     }
1983   }
1984   else
1985   if (query_string->mode == IMG_CONV_MODE_WALLPAPER && query_string->name != NULL) {
1986     if (query_string->count == -1 && query_string->offset == -1) {
1987       chxj_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
1988     }
1989     else
1990     if (query_string->count == -2 && query_string->offset == -1) {
1991       chxj_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
1992     }
1993     else { 
1994       chxj_set_content_type(r, "application/x-up-download");
1995       contentLength = apr_psprintf(r->pool, "%ld", query_string->count);
1996       apr_table_setn(r->headers_out, "Content-Length", (const char*)contentLength);
1997   
1998       DBG(r, "REQ[%X] Content-Length:[%d]", TO_ADDR(r), (int)st.size);
1999     }
2000   }
2001   if (conf->image_copyright) {
2002     DBG(r, "REQ[%X] Add COPYRIGHT Header for SoftBank [%s]", TO_ADDR(r), conf->image_copyright);
2003     if (spec->html_spec_type == CHXJ_SPEC_Jhtml ||  spec->html_spec_type == CHXJ_SPEC_Jxhtml) {
2004       apr_table_setn(r->headers_out, "x-jphone-copyright", "no-transfer");
2005     }
2006   }
2007   
2008   DBG(r, "REQ[%X] end s_header_only_cache_file()", TO_ADDR(r));
2009   return OK;
2010 }
2011
2012
2013 static void 
2014 s_init_serial_pattern(apr_pool_t *p)
2015 {
2016   if (!v_docomo_serial_pattern1) {
2017     v_docomo_serial_pattern1 = chxj_compile_for_preg_replace(p, "/ser[^;\\)]+");
2018   }  
2019   if (!v_docomo_serial_pattern2) {
2020     v_docomo_serial_pattern2 = chxj_compile_for_preg_replace(p, ";ser[^;\\)]+");
2021   }  
2022   if (!v_docomo_serial_pattern3) {
2023     v_docomo_serial_pattern3 = chxj_compile_for_preg_replace(p, ";icc[^;\\)]+");
2024   }  
2025   if (!v_softbank_serial_pattern1) {
2026     v_softbank_serial_pattern1 = chxj_compile_for_preg_replace(p, "/SN[0-9a-zA-Z]+ ");
2027   }  
2028 }
2029
2030
2031 static char *
2032 s_create_workfile_name(
2033                 request_rec          *r, 
2034                 mod_chxj_config      *conf, 
2035                 const char           *user_agent, 
2036                 query_string_param_t *qsp)
2037 {
2038   int  ii;
2039   int  jj;
2040   int  len;
2041   char *w = apr_palloc(r->pool, 256);
2042   char *fname;
2043   char *new_user_agent;
2044
2045   s_init_serial_pattern(r->server->process->pool);
2046
2047   /* for DoCoMo */
2048   new_user_agent = chxj_preg_replace(r->pool, v_docomo_serial_pattern1, "", user_agent);
2049   new_user_agent = chxj_preg_replace(r->pool, v_docomo_serial_pattern2, "", new_user_agent);
2050   new_user_agent = chxj_preg_replace(r->pool, v_docomo_serial_pattern3, "", new_user_agent);
2051
2052   /* for SoftBank */
2053   new_user_agent = chxj_preg_replace(r->pool, v_softbank_serial_pattern1, " ", new_user_agent);
2054
2055   DBG(r, "REQ[%X] old user_agent:[%s] ==> new user_agent:[%s]", TO_ADDR(r),user_agent, new_user_agent);
2056
2057
2058   memset(w, 0, 256);
2059   switch (qsp->mode) {
2060   case IMG_CONV_MODE_THUMBNAIL:
2061     fname = apr_psprintf(r->pool, "%s.%s.thumbnail", r->filename, new_user_agent);
2062     DBG(r, "REQ[%X] mode=thumbnail [%s]", TO_ADDR(r),fname);
2063     break;
2064
2065   case IMG_CONV_MODE_WALLPAPER:
2066   case IMG_CONV_MODE_EZGET:
2067     fname = apr_psprintf(r->pool, "%s.%s.wallpaper", r->filename, new_user_agent);
2068     DBG(r, "REQ[%X] mode=WallPaper [%s]", TO_ADDR(r),fname);
2069     break;
2070
2071   case IMG_CONV_MODE_NORMAL:
2072   default:
2073
2074     fname = apr_psprintf(r->pool, "%s.%s", r->filename, new_user_agent);
2075
2076     if (qsp->width)
2077       fname = apr_psprintf(r->pool, "%s.w%d", fname, qsp->width);
2078
2079     if (qsp->height)
2080       fname = apr_psprintf(r->pool, "%s.h%d", fname, qsp->height);
2081
2082     DBG(r,"REQ[%X] mode=normal [%s]", TO_ADDR(r),fname);
2083     break;
2084   }
2085   if (qsp->ua_flag == UA_IGN) {
2086     fname = apr_psprintf(r->pool, "%s.IGN", fname);
2087   }
2088
2089   len = strlen(fname);
2090   jj=0;
2091   for  (ii=0; ii<len; ii++) {
2092     if (fname[ii] == '/' 
2093     ||  fname[ii] == ' ' 
2094     ||  fname[ii] == '-' 
2095     ||  fname[ii] == '.' 
2096     ||  fname[ii] == '(' 
2097     ||  fname[ii] == ')') {
2098       w[jj++] = '_';
2099     }
2100     else {
2101       w[jj++] = fname[ii];
2102     }
2103   }
2104
2105   return apr_psprintf(r->pool, "%s/%s.%s", conf->image_cache_dir,w,CACHEDATA_EXT);
2106 }
2107
2108
2109 static unsigned short
2110 s_add_crc(const char *writedata, apr_size_t writebyte)
2111 {
2112   unsigned short crc = 0xffff;
2113   apr_size_t     ii;
2114   unsigned char  ch;
2115
2116   for(ii=0;ii<writebyte;ii++) {
2117     ch  = writedata[ii];
2118     crc = AU_CRC_TBL[(crc>>8^ch)&0xff]^(crc<<8);
2119   }
2120   return crc;
2121 }
2122
2123
2124 int
2125 chxj_trans_name(request_rec *r)
2126 {
2127   const char      *ccp;
2128   char            *docroot;
2129   int             len;
2130   apr_finfo_t     st;
2131   apr_status_t    rv;
2132   mod_chxj_config *conf;
2133   int             ii;
2134   char            *ext[] = {
2135           "jpg",
2136           "JPG",
2137           "jpeg",
2138           "JPEG",
2139           "png",
2140           "PNG",
2141           "bmp",
2142           "BMP",
2143           "gif",
2144           "GIF",
2145           "qrc",    /* QRCode出力用ファイルの拡張子 */
2146           "",
2147   };
2148   char     *fname = NULL;
2149   char     *idx;
2150   char     *filename_sv;
2151   int      do_ext_check = TRUE;
2152   int      next_ok      = FALSE;
2153
2154   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
2155
2156   conf = chxj_get_module_config(r->per_dir_config, &chxj_module);
2157
2158   if (conf == NULL) {
2159     DBG(r,"REQ[%X]  conf is null[%s]", TO_ADDR(r),r->uri);
2160     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
2161     return DECLINED;
2162   }
2163
2164   if (conf->image != CHXJ_IMG_ON) {
2165     DBG(r,"REQ[%X] conf not found",TO_ADDR(r));
2166     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
2167     return DECLINED;
2168   }
2169
2170
2171   DBG(r,"REQ[%X] Match URI[%s]", TO_ADDR(r),r->uri);
2172
2173
2174   if (r->filename == NULL) 
2175     r->filename = apr_pstrdup(r->pool, r->uri);
2176
2177   filename_sv = NULL;
2178   if ((idx = strchr(r->filename, ':')) != NULL) 
2179     filename_sv = idx+1;
2180   else 
2181     filename_sv = r->filename;
2182
2183   DBG(r,"REQ[%X] r->filename[%s]", TO_ADDR(r),filename_sv);
2184
2185   ccp = ap_document_root(r);
2186   if (ccp == NULL)
2187     return HTTP_INTERNAL_SERVER_ERROR;
2188
2189   docroot = apr_pstrdup(r->pool, ccp);
2190   len = strlen(docroot);
2191
2192   if (docroot[len-1] == '/') 
2193     docroot[len-1] = '\0';
2194
2195
2196   if (r->server->path 
2197   &&  *filename_sv == *r->server->path 
2198   &&  strncmp(filename_sv, r->server->path, r->server->pathlen) == 0)
2199     filename_sv = apr_pstrcat(r->pool, docroot, (filename_sv + r->server->pathlen), NULL);
2200   else
2201     filename_sv = apr_pstrcat(r->pool, docroot, filename_sv, NULL);
2202
2203   DBG(r,"REQ[%X] URI[%s]", TO_ADDR(r),filename_sv);
2204
2205   do_ext_check = TRUE;
2206   for (ii=0; ii<(int)(sizeof(ext)/sizeof(ext[0])); ii++) {
2207     char* pos = strrchr(filename_sv, '.');
2208     if (pos && pos++) {
2209       if (strcasecmp(pos, ext[ii]) == 0) {
2210         do_ext_check = FALSE;
2211         fname = apr_psprintf(r->pool, "%s", filename_sv);
2212         break;
2213       }
2214     }
2215   }
2216
2217   if (do_ext_check) {
2218     for (ii=0; ii<(int)(sizeof(ext)/sizeof(ext[0])); ii++) {
2219       if (strlen(ext[ii]) == 0) {
2220         fname = apr_psprintf(r->pool, "%s", filename_sv);
2221       }
2222       else 
2223         fname = apr_psprintf(r->pool, "%s.%s", filename_sv, ext[ii]);
2224   
2225       DBG(r,"REQ[%X] search [%s]", TO_ADDR(r),fname);
2226   
2227       rv = apr_stat(&st, fname, APR_FINFO_MIN, r->pool);
2228       if (rv == APR_SUCCESS) {
2229         if (st.filetype != APR_DIR)
2230           break;
2231       }
2232   
2233       fname = NULL;
2234     }
2235   }
2236   if (fname == NULL) {
2237     DBG(r,"REQ[%X] NotFound [%s]", TO_ADDR(r),r->filename);
2238     return DECLINED;
2239   }
2240   for (ii=0; ii<(int)(sizeof(ext)/sizeof(ext[0])); ii++) {
2241     char* pos = strrchr(fname, '.');
2242     if (pos && pos++) {
2243       if (strcasecmp(pos, ext[ii]) == 0) {
2244         next_ok = TRUE;
2245         break;
2246       }
2247     }
2248   }
2249
2250   if (! next_ok)  {
2251     DBG(r,"REQ[%X] NotFound [%s]", TO_ADDR(r),r->filename);
2252     return DECLINED;
2253   }
2254
2255   if (r->handler == NULL || strcasecmp(r->handler, "chxj-qrcode") != 0) {
2256     DBG(r,"REQ[%X] Found [%s]", TO_ADDR(r),fname);
2257
2258     r->filename = apr_psprintf(r->pool, "%s", fname);
2259   
2260     if (strcasecmp("qrc", ext[ii]) == 0)
2261       r->handler = apr_psprintf(r->pool, "chxj-qrcode");
2262     else
2263       r->handler = apr_psprintf(r->pool, "chxj-picture");
2264   }
2265   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
2266   return OK;
2267 }
2268
2269
2270
2271 static int
2272 s_chxj_trans_name2(request_rec *r)
2273 {
2274   apr_finfo_t     st;
2275   apr_status_t    rv;
2276   mod_chxj_config *conf;
2277   int             ii;
2278   char            *ext[] = {
2279           "jpg",
2280           "JPG",
2281           "jpeg",
2282           "JPEG",
2283           "png",
2284           "PNG",
2285           "bmp",
2286           "BMP",
2287           "gif",
2288           "GIF",
2289           "qrc",    /* QRCode出力用ファイルの拡張子 */
2290           "",
2291   };
2292   char     *fname = NULL;
2293   char     *filename_sv;
2294   int      do_ext_check = TRUE;
2295   int      next_ok      = FALSE;
2296
2297   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
2298
2299   conf = chxj_get_module_config(r->per_dir_config, &chxj_module);
2300
2301   if (conf == NULL) {
2302     DBG(r, "REQ[%X] conf is null[%s]", TO_ADDR(r), r->uri);
2303     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
2304     return DECLINED;
2305   }
2306
2307   if (conf->image != CHXJ_IMG_ON) {
2308     DBG(r, "REQ[%X] ImageEngineOff", TO_ADDR(r));
2309     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
2310     return DECLINED;
2311   }
2312
2313
2314   DBG(r,"REQ[%X] Match URI[%s]", TO_ADDR(r),r->uri);
2315
2316   if (r->filename == NULL) {
2317     DBG(r, "REQ[%X] r->filename is null", TO_ADDR(r));
2318     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
2319     return DECLINED;
2320   }
2321      
2322   filename_sv = r->filename;
2323
2324   DBG(r,"REQ[%x] r->filename[%s]", TO_ADDR(r), filename_sv);
2325
2326   do_ext_check = TRUE;
2327   for (ii=0; ii<(int)(sizeof(ext)/sizeof(ext[0])); ii++) {
2328     char* pos = strrchr(filename_sv, '.');
2329     if (pos && pos++) {
2330       if (strcasecmp(pos, ext[ii]) == 0) {
2331         do_ext_check = FALSE;
2332         fname = apr_psprintf(r->pool, "%s", filename_sv);
2333         break;
2334       }
2335     }
2336   }
2337
2338   if (do_ext_check) {
2339     for (ii=0; ii<(int)(sizeof(ext)/sizeof(ext[0])); ii++) {
2340       if (strlen(ext[ii]) == 0) {
2341         fname = apr_psprintf(r->pool, "%s", filename_sv);
2342       }
2343       else 
2344         fname = apr_psprintf(r->pool, "%s.%s", filename_sv, ext[ii]);
2345   
2346       DBG(r,"REQ[%X] search [%s]", TO_ADDR(r),fname);
2347   
2348       rv = apr_stat(&st, fname, APR_FINFO_MIN, r->pool);
2349       if (rv == APR_SUCCESS) {
2350         if (st.filetype != APR_DIR)
2351           break;
2352       }
2353   
2354       fname = NULL;
2355     }
2356   }
2357   if (fname == NULL) {
2358     DBG(r,"REQ[%X] NotFound [%s]", TO_ADDR(r),r->filename);
2359     return DECLINED;
2360   }
2361   for (ii=0; ii<(int)(sizeof(ext)/sizeof(ext[0])); ii++) {
2362     char* pos = strrchr(fname, '.');
2363     if (pos && pos++) {
2364       if (strcasecmp(pos, ext[ii]) == 0) {
2365         next_ok = TRUE;
2366         break;
2367       }
2368     }
2369   }
2370
2371   if (! next_ok)  {
2372     DBG(r,"REQ[%X] NotFound [%s]", TO_ADDR(r),r->filename);
2373     return DECLINED;
2374   }
2375
2376   if (r->handler == NULL || strcasecmp(r->handler, "chxj-qrcode") != 0) {
2377     DBG(r,"REQ[%X] Found [%s]", TO_ADDR(r),fname);
2378
2379     r->filename = apr_psprintf(r->pool, "%s", fname);
2380   
2381     if (strcasecmp("qrc", ext[ii]) == 0)
2382       r->handler = apr_psprintf(r->pool, "chxj-qrcode");
2383     else
2384       r->handler = apr_psprintf(r->pool, "chxj-picture");
2385   }
2386   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
2387   return OK;
2388 }
2389
2390
2391
2392 /**
2393  * It converts it from QUERYSTRING.
2394  *
2395  * @param r   [i]
2396  */
2397 static query_string_param_t *
2398 s_get_query_string_param(request_rec *r)
2399 {
2400   char *pair;
2401   char *name;
2402   char *value;
2403   char *pstate;
2404   char *vstate;
2405   char *s;
2406   query_string_param_t *param;
2407
2408   s = apr_pstrdup(r->pool, r->parsed_uri.query);
2409   param = apr_palloc(r->pool, sizeof(query_string_param_t));
2410   param->mode       = IMG_CONV_MODE_NORMAL;
2411   param->user_agent = NULL;
2412   param->ua_flag    = UA_USE;
2413   param->name       = NULL;
2414   param->offset     = 0;
2415   param->count      = 0;
2416   param->width      = 0;
2417   param->height     = 0;
2418
2419   if (s == NULL) return param;
2420
2421   for (;;) {
2422     if ((pair = apr_strtok(s, "&", &pstate)) == NULL) break;
2423     s = NULL;
2424
2425     name  = apr_strtok(pair, "=", &vstate);
2426     value = apr_strtok(NULL, "=", &vstate);
2427
2428     switch (*name) {
2429     case 'm':
2430     case 'M':
2431       if (value && (strcasecmp(name, "mode") == 0 || strcasecmp(name, "m") == 0)) {
2432
2433         switch (*value) {
2434         case 't':
2435         case 'T':
2436           if (strcasecmp(value, "thumbnail") == 0 || strcasecmp(value, "tb") == 0)
2437             param->mode = IMG_CONV_MODE_THUMBNAIL;
2438           break;
2439   
2440         case 'w':
2441         case 'W':
2442           if (strcasecmp(value, "WP") == 0 || strcasecmp(value, "WallPaper") == 0)
2443             param->mode = IMG_CONV_MODE_WALLPAPER;
2444           break;
2445   
2446         case 'e':
2447         case 'E':
2448           if (strcasecmp(value, "EZGET") == 0)
2449             param->mode = IMG_CONV_MODE_EZGET;
2450           break;
2451         default:
2452           break;
2453         }
2454       }
2455       break;
2456
2457     case 'u':
2458     case 'U':
2459       if (value && (strcasecmp(name, "ua") == 0 || strcasecmp(name, "user-agent") == 0)) {
2460         ap_unescape_url(value);
2461
2462         if ((*value == 'i' || *value == 'I') && strcasecmp(value, "IGN") == 0)
2463           param->ua_flag = UA_IGN;
2464
2465         param->user_agent = apr_pstrdup(r->pool, value);
2466       }
2467       break;
2468
2469     case 'n':
2470     case 'N':
2471       if (value && strcasecmp(name, "name") == 0)
2472         param->name = apr_pstrdup(r->pool, value);
2473       break;
2474
2475     case 'o':
2476     case 'O':
2477       if (value && strcasecmp(name, "offset") == 0 && (! chxj_chk_numeric(value)))
2478         param->offset = chxj_atoi(value);
2479
2480       break;
2481
2482     case 'c':
2483     case 'C':
2484       if (value && strcasecmp(name, "count") == 0 && (! chxj_chk_numeric(value)))
2485         param->count = chxj_atoi(value);
2486       break;
2487
2488     case 'w':
2489     case 'W':
2490       if (value && strcasecmp(name, "w") == 0 && (! chxj_chk_numeric(value)))
2491         param->width = chxj_atoi(value);
2492       break;
2493
2494     case 'h':
2495     case 'H':
2496       if (value && strcasecmp(name, "h") == 0 && (! chxj_chk_numeric(value)))
2497         param->height = chxj_atoi(value);
2498       break;
2499
2500     default:
2501       break;
2502     }
2503   }
2504
2505   if (param->mode == IMG_CONV_MODE_NORMAL && param->name)
2506     param->mode = IMG_CONV_MODE_WALLPAPER;
2507
2508   return param;
2509 }
2510
2511
2512 static char *
2513 s_add_comment_to_png(request_rec *r, char *data, apr_size_t *len)
2514 {
2515   char *result = NULL;
2516 #define PNG_COPYRIGHT_KEY "Copyright"
2517 #define PNG_COPYRIGHT_VAL "kddi_copyright=on,copy=NO"
2518 #define PNG_SIG_AND_IHDR_SZ (33)
2519   char *key = PNG_COPYRIGHT_KEY;
2520   apr_size_t klen = sizeof(PNG_COPYRIGHT_KEY)-1;
2521   char *val = PNG_COPYRIGHT_VAL;
2522   apr_size_t vlen = sizeof(PNG_COPYRIGHT_VAL)-1;
2523   apr_pool_t *pool;
2524   apr_size_t total_tEXt_size;
2525   apr_size_t tEXt_data_size;
2526   apr_size_t pos;
2527   apr_size_t ii;
2528   char *buf;
2529   char *valbuf;
2530   uint32_t crc;
2531   mod_chxj_config *conf = chxj_get_module_config(r->per_dir_config, &chxj_module);
2532
2533   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
2534   if (conf->image_copyright) {
2535     apr_pool_create(&pool, r->pool);
2536
2537     valbuf = apr_psprintf(pool, "%s,%s", val, conf->image_copyright);
2538     vlen = strlen(valbuf);
2539   
2540     /* total_size = length + "tEXt" + "Copyright" + '\0' + val + crc */
2541     total_tEXt_size = 4 + 4 + klen + vlen + 1 + 4;
2542     result = apr_palloc(pool, total_tEXt_size + *len);
2543     if (!result) {
2544       DBG(r, "REQ[%X] memory allocation error.", TO_ADDR(r));
2545       return NULL;
2546     }
2547     pos = PNG_SIG_AND_IHDR_SZ;
2548     memcpy(result, data, pos); /* 33 = SIGNATURE + IHDR */
2549     tEXt_data_size = klen + 1 + vlen;
2550     result[pos + 0] = tEXt_data_size >> 24;
2551     result[pos + 1] = tEXt_data_size >> 16;
2552     result[pos + 2] = tEXt_data_size >> 8;
2553     result[pos + 3] = tEXt_data_size;
2554     pos += 4;
2555     buf = apr_palloc(pool, 4 + klen + 1 + vlen);
2556     memcpy(&buf[0], "tEXt", 4); 
2557     memcpy(&buf[4], key, klen);
2558     buf[4+klen] = 0;
2559     memcpy(&buf[4+klen+1], valbuf, vlen);
2560     
2561     
2562     DBG(r, "REQ[%X] buf:[%s]", TO_ADDR(r), buf);
2563   
2564     crc = 0xffffffff;
2565     for (ii = 0; ii < 4 + tEXt_data_size; ii++) {
2566       crc = AU_CRC_TBL[(crc ^ buf[ii]) & 0xff] ^ (crc >> 8);
2567     }
2568     crc ^= 0xffffffff;
2569     memcpy(&result[pos], buf, 4 + klen + 1 + vlen);
2570     pos += (4 + klen + 1 + vlen);
2571     result[pos + 0] = crc >> 24;
2572     result[pos + 1] = crc >> 16;
2573     result[pos + 2] = crc >> 8;
2574     result[pos + 3] = crc;
2575     pos += 4;
2576     memcpy(&result[pos], &data[PNG_SIG_AND_IHDR_SZ] , *len - PNG_SIG_AND_IHDR_SZ);
2577     *len = *len + total_tEXt_size;
2578     DBG(r, "REQ[%X] writebyte:[%d]", TO_ADDR(r), (unsigned int)*len);
2579   }
2580   else {
2581     result = data;
2582   }
2583   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
2584 #undef PNG_SIG_AND_IHDR_SZ
2585 #undef PNG_COPYRIGHT_KEY
2586 #undef PNG_COPYRIGHT_VAL
2587   return result;
2588 }
2589 /*
2590  * vim:ts=2 et
2591  */