OSDN Git Service

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