OSDN Git Service

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