OSDN Git Service

* change writting.
[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 static query_string_param_t* s_get_query_string_param(request_rec *r);
185 static unsigned short s_add_crc(        const char* writedata, 
186                                         apr_size_t witebyte);
187 static MagickWand* s_fixup_size(MagickWand* , 
188                                         request_rec* r, 
189                                         device_table* spec, 
190                                         query_string_param_t *qsp);
191 static MagickWand* s_fixup_color(MagickWand* magick_wand, 
192                                  request_rec* r, 
193                                  device_table* spec, 
194                                  img_conv_mode_t mode);
195 static MagickWand* s_fixup_depth(MagickWand* magick_wand, 
196                                  request_rec* r, device_table* spec);
197 static MagickWand* s_img_down_sizing(MagickWand* magick_wand, 
198                                 request_rec* r, device_table* spec);
199 static MagickWand* s_add_copyright(
200                           MagickWand* magick_wand,
201                           request_rec* r,
202                           device_table* spec);
203 static char* s_create_blob_data(request_rec* r,
204                    device_table* spec,
205                    query_string_param_t *qsp,
206                    char* indata,
207                    apr_size_t* len);
208
209 static int s_img_conv_format_from_file(
210                 request_rec*          r, 
211                 mod_chxj_config*    conf, 
212                 const char*           user_agent,
213                 query_string_param_t* qsp,
214                 device_table*       spec);
215
216 int 
217 chxj_img_conv_format_handler(request_rec* r)
218 {
219   mod_chxj_config*      conf;
220   query_string_param_t* qsp;
221   char*                 user_agent;
222   device_table*       spec;
223   chxjconvrule_entry* entryp;
224
225   DBG(r, "start chxj_img_conv_format_handler()");
226   
227   if ((*r->handler != 'c' && *r->handler != 'C') 
228   ||  (strcasecmp(r->handler, "chxj-picture")
229   &&  strcasecmp(r->handler, "chxj-qrcode"))) {
230     DBG(r, "end chxj_img_conv_format_handler()");
231     return DECLINED;
232   }
233
234   qsp = s_get_query_string_param(r);
235   conf = ap_get_module_config(r->per_dir_config, &chxj_module);
236   if (conf == NULL) {
237     DBG(r, "end chxj_img_conv_format_handler() conf is null");
238     return DECLINED;
239   }
240
241   if (strcasecmp(r->handler, "chxj-qrcode") == 0 &&  conf->image == CHXJ_IMG_OFF) 
242     return DECLINED;
243
244
245   /*------------------------------------------------------------------------*/
246   /* get UserAgent from http header                                         */
247   /*------------------------------------------------------------------------*/
248   /*--------------------------------------------------------------------------*/
249   /* User-Agent to spec                                                       */
250   /*--------------------------------------------------------------------------*/
251   if (qsp->user_agent) {
252     user_agent = apr_pstrdup(r->pool, qsp->user_agent);
253   }
254   else {
255     entryp = chxj_apply_convrule(r, conf->convrules);
256     if (entryp && entryp->user_agent) {
257       user_agent = (char*)apr_table_get(r->headers_in, CHXJ_HTTP_USER_AGENT);
258     }
259     else {
260       user_agent = (char*)apr_table_get(r->headers_in, HTTP_USER_AGENT);
261     }
262   }
263
264
265
266   if (qsp->ua_flag == UA_IGN)
267     spec = &v_ignore_spec;
268   else
269     spec = chxj_specified_device(r, user_agent);
270
271   DBG1(r,"found device_name=[%s]", spec->device_name);
272   DBG1(r,"User-Agent=[%s]", user_agent);
273
274   if (spec->width == 0 || spec->heigh == 0)
275     return DECLINED;
276
277   return s_img_conv_format_from_file(r, conf, user_agent, qsp, spec);
278 }
279
280
281
282 /**
283  * It converts it from ImageData corresponding to each model.
284  *
285  * @param r   [i]
286  * @param src [i]   It is former image binary data.
287  * @param len [i/o] It is length of former image binary data.
288  */
289 char*
290 chxj_exchange_image(request_rec *r, const char** src, apr_size_t* len)
291 {
292   mod_chxj_config*      conf;
293   query_string_param_t* qsp;
294   char*                 user_agent;
295   device_table*         spec;
296   char*                 dst;
297   char*                 conv_check;
298   chxjconvrule_entry* entryp;
299
300   DBG(r, "start chxj_exchange_image()");
301
302   conv_check = (char*)apr_table_get(r->headers_in, "CHXJ_IMG_CONV");
303   if (conv_check) {
304     DBG(r, "end chxj_exchnage_image() already convert.");
305     return NULL;
306   }
307
308
309   qsp = s_get_query_string_param(r);
310   conf = ap_get_module_config(r->per_dir_config, &chxj_module);
311   if (conf == NULL) {
312     DBG(r, "end chxj_exchange_image()");
313     return NULL;
314   }
315
316   /*--------------------------------------------------------------------------*/
317   /* User-Agent to spec                                                       */
318   /*--------------------------------------------------------------------------*/
319   if (qsp->user_agent) {
320     user_agent = apr_pstrdup(r->pool, qsp->user_agent);
321   }
322   else {
323     entryp = chxj_apply_convrule(r, conf->convrules);
324     if (entryp && entryp->user_agent) {
325       user_agent = (char*)apr_table_get(r->headers_in, CHXJ_HTTP_USER_AGENT);
326     }
327     else {
328       user_agent = (char*)apr_table_get(r->headers_in, HTTP_USER_AGENT);
329     }
330   }
331
332   if (qsp->ua_flag == UA_IGN)
333     spec = &v_ignore_spec;
334   else
335     spec = chxj_specified_device(r, user_agent);
336
337   DBG1(r,"found device_name=[%s]", spec->device_name);
338   DBG1(r, "User-Agent=[%s]", user_agent);
339
340   if (spec->width == 0 || spec->heigh == 0) 
341     return NULL;
342
343   dst = s_create_blob_data(r, spec, qsp, (char*)*src, len);
344   if (dst == NULL) 
345     *len = 0;
346
347   DBG(r, "end chxj_exchange_image()");
348
349   return dst;
350 }
351
352 static int
353 s_img_conv_format_from_file(
354                 request_rec*          r, 
355                 mod_chxj_config*    conf, 
356                 const char*           user_agent,
357                 query_string_param_t* qsp,
358                 device_table*       spec)
359 {
360   apr_status_t   rv;
361   apr_finfo_t    st;
362   apr_finfo_t    cache_st;
363   char*          tmpfile;
364
365   /*--------------------------------------------------------------------------*/
366   /* Create Workfile Name                                                     */
367   /*--------------------------------------------------------------------------*/
368   tmpfile = s_create_workfile(r, conf, user_agent, qsp);
369   DBG1(r,"workfile=[%s]", tmpfile);
370
371   rv = apr_stat(&st, r->filename, APR_FINFO_MIN, r->pool);
372   if (rv != APR_SUCCESS)
373     return HTTP_NOT_FOUND;
374
375
376   DBG1(r,"found [%s]", r->filename);
377   rv = apr_stat(&cache_st, tmpfile, APR_FINFO_MIN, r->pool);
378   DBG1(r,"found [%s]", r->filename);
379
380   if (rv != APR_SUCCESS || cache_st.ctime < st.mtime) {
381     /*------------------------------------------------------------------------*/
382     /* It tries to make the cash file when it doesn't exist or there is       */
383     /* change time later since the making time of the cash file.              */
384     /*------------------------------------------------------------------------*/
385     rv = s_create_cache_file(r,tmpfile, spec, &st, qsp);
386     if (rv != OK)
387       return rv;
388   }
389
390   DBG1(r,"color=[%d]", spec->color);
391   if (! r->header_only)  {
392     rv = s_send_cache_file(spec, qsp,r, tmpfile);
393     if (rv != OK) 
394       return rv;
395   }
396   else {
397     rv = s_header_only_cache_file(spec, qsp, r, tmpfile);
398     if (rv != OK) 
399       return rv;
400   }
401   apr_table_setn(r->headers_in, "CHXJ_IMG_CONV", "done");
402
403   DBG(r,"end chxj_img_conv_format");
404
405   return OK;
406 }
407
408
409 static apr_status_t
410 s_create_cache_file(request_rec*       r, 
411                        const char*     tmpfile, 
412                        device_table* spec, 
413                        apr_finfo_t*    st, 
414                        query_string_param_t *qsp)
415 {
416   apr_status_t       rv;
417   apr_size_t         readbyte;
418   apr_size_t         writebyte;
419   unsigned short     crc;
420   img_conv_mode_t    mode = qsp->mode;
421
422   char*              writedata = NULL;
423   char*              readdata  = NULL;
424
425   apr_file_t*        fout;
426   apr_file_t*        fin;
427
428   MagickWand*        magick_wand;
429
430   if ((*r->handler == 'c' || *r->handler == 'C') 
431   &&  strcasecmp(r->handler, "chxj-qrcode") == 0) {
432     /*------------------------------------------------------------------------*/
433     /* QRCODEÍѤΥե¡¥¤¥ë¤Î¾ì¹ç                                               */
434     /*------------------------------------------------------------------------*/
435     Doc       doc;
436     Node*     root;
437     qr_code_t qrcode;
438     int       sts;
439
440     memset(&doc,    0, sizeof(Doc));
441     memset(&qrcode, 0, sizeof(qr_code_t));
442     doc.r = r;
443     doc.parse_mode  = PARSE_MODE_CHTML;
444     qrcode.doc      = &doc;
445     qrcode.r        = r;
446
447     qs_init_malloc(&doc);
448
449     root = qs_parse_file(&doc, r->filename);
450
451     chxj_qrcode_node_to_qrcode(&qrcode, root);
452
453     qs_all_free(&doc,QX_LOGMARK);
454
455     sts = chxj_qrcode_create_image_data(&qrcode, &readdata, &readbyte);
456     if (sts != OK) {
457       ERR(r, "qrcode create failed.");
458       return sts;
459     }
460   }
461   else {
462     /*------------------------------------------------------------------------*/
463     /* Ä̾ï¤Î¥¤¥á¡¼¥¸¥Õ¥¡¥¤¥ë¤Î¾ì¹ç                                           */
464     /*------------------------------------------------------------------------*/
465     rv = apr_file_open(&fin, 
466                     r->filename, 
467                     APR_READ|APR_BINARY ,
468                     APR_OS_DEFAULT, 
469                     r->pool);
470     if (rv != APR_SUCCESS) {
471       DBG1(r,"file open failed.[%s]", r->filename);
472       return HTTP_NOT_FOUND;
473     }
474   
475     readdata = apr_palloc(r->pool, st->size);
476     rv = apr_file_read_full(fin, (void*)readdata, st->size, &readbyte);
477     if (rv != APR_SUCCESS || readbyte != st->size) {
478       DBG1(r,"file read failed.[%s]", r->filename);
479       apr_file_close(fin);
480   
481       return HTTP_NOT_FOUND;
482     }
483   }
484   DBG(r,"start img convert");
485
486
487   magick_wand = NewMagickWand();
488   if (MagickReadImageBlob(magick_wand,readdata, readbyte) == MagickFalse) {
489     EXIT_MAGICK_ERROR();
490     return HTTP_NOT_FOUND;
491   }
492
493   /*
494    * The size of the image is changed.
495    */
496   DBG(r,"call s_fixup_size()");
497
498   if ((magick_wand = s_fixup_size(magick_wand, r, spec, qsp)) == NULL) 
499     return HTTP_NOT_FOUND;
500
501   /*
502    * The colors of the image is changed.
503    */
504   DBG(r,"call s_fixup_color()");
505
506   if ((magick_wand = s_fixup_color(magick_wand, r,spec, mode)) == NULL) 
507     return HTTP_NOT_FOUND;
508
509   /*
510    * DEPTH of the image is changed.
511    */
512   DBG(r,"call s_fixup_depth()");
513
514   if ((magick_wand = s_fixup_depth(magick_wand, r, spec)) == NULL) 
515     return HTTP_NOT_FOUND;
516
517
518
519   DBG(r,"start convert and compression");
520
521   if (spec->available_jpeg) {
522     if (MagickSetImageCompression(magick_wand,JPEGCompression) == MagickFalse) {
523       EXIT_MAGICK_ERROR();
524       return HTTP_NOT_FOUND;
525     }
526
527     if (MagickSetImageFormat(magick_wand, "jpg") == MagickFalse) {
528       EXIT_MAGICK_ERROR();
529       return HTTP_NOT_FOUND;
530     }
531
532     if (MagickStripImage(magick_wand) == MagickFalse) {
533       EXIT_MAGICK_ERROR();
534       return HTTP_NOT_FOUND;
535     }
536
537     if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL)
538       return HTTP_NOT_FOUND;
539
540     r->content_type = apr_psprintf(r->pool, "image/jpeg");
541     DBG(r,"convert to jpg");
542   }
543   else
544   if (spec->available_png) {
545
546     if (MagickSetImageCompression(magick_wand,ZipCompression) == MagickFalse) {
547       EXIT_MAGICK_ERROR();
548       return HTTP_NOT_FOUND;
549     }
550
551     if (MagickSetImageFormat(magick_wand, "png") == MagickFalse) {
552       EXIT_MAGICK_ERROR();
553       return HTTP_NOT_FOUND;
554     }
555
556     if (MagickStripImage(magick_wand) == MagickFalse) {
557       EXIT_MAGICK_ERROR();
558       return HTTP_NOT_FOUND;
559     }
560
561     if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL) 
562       return HTTP_NOT_FOUND;
563
564     r->content_type = apr_psprintf(r->pool, "image/png");
565     DBG(r, "convert to png");
566   }
567   else
568   if (spec->available_gif) {
569
570     if (MagickSetImageCompression(magick_wand,LZWCompression) == MagickFalse) {
571       EXIT_MAGICK_ERROR();
572       return HTTP_NOT_FOUND;
573     }
574
575     if (MagickSetImageFormat(magick_wand, "gif") == MagickFalse) {
576       EXIT_MAGICK_ERROR();
577       return HTTP_NOT_FOUND;
578     }
579
580     if (MagickStripImage(magick_wand) == MagickFalse) {
581       EXIT_MAGICK_ERROR();
582       return HTTP_NOT_FOUND;
583     }
584
585     if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL) 
586       return HTTP_NOT_FOUND;
587
588     r->content_type = apr_psprintf(r->pool, "image/gif");
589
590     DBG(r,"convert to gif");
591   }
592   else
593   if (spec->available_bmp2 || spec->available_bmp4) {
594
595     if (MagickSetImageCompression(magick_wand,NoCompression) == MagickFalse) {
596       EXIT_MAGICK_ERROR();
597       return HTTP_NOT_FOUND;
598     }
599
600     if (MagickSetImageFormat(magick_wand, "bmp") == MagickFalse) {
601       EXIT_MAGICK_ERROR();
602       return HTTP_NOT_FOUND;
603     }
604
605     if (MagickStripImage(magick_wand) == MagickFalse) {
606       EXIT_MAGICK_ERROR();
607       return HTTP_NOT_FOUND;
608     }
609
610     if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL) 
611       return HTTP_NOT_FOUND;
612
613     r->content_type = apr_psprintf(r->pool, "image/bmp");
614
615     DBG(r, "convert to bmp(unsupported)");
616   }
617
618   /*
619    * Add Comment (Copyright and so on.)
620    */
621   DBG(r, "call s_add_copyright()");
622
623   if ((magick_wand = s_add_copyright(magick_wand, r, spec)) == NULL) 
624     return HTTP_NOT_FOUND;
625
626   writedata = (char*)MagickGetImageBlob(magick_wand, &writebyte);
627
628   if (! writebyte) {
629     DestroyMagickWand(magick_wand);
630     ERR1(r,"convert failure to Jpeg [%s]", tmpfile);
631
632     return HTTP_INTERNAL_SERVER_ERROR;
633   }
634
635   DBG(r, "end convert and compression");
636   
637   /* to cache */
638   rv = apr_file_open(&fout, tmpfile,
639                   APR_WRITE| APR_CREATE | APR_BINARY | APR_SHARELOCK ,APR_OS_DEFAULT,
640                   r->pool);
641   if (rv != APR_SUCCESS) {
642     DestroyMagickWand(magick_wand);
643     ERR1(r,"file open error.[%s]", tmpfile);
644     return HTTP_INTERNAL_SERVER_ERROR;
645   }
646
647   rv = apr_file_write(fout, (void*)writedata, &writebyte);
648   if (rv != APR_SUCCESS) {
649     DestroyMagickWand(magick_wand);
650     apr_file_close(fout);
651     return HTTP_INTERNAL_SERVER_ERROR;
652   }
653
654   /*
655    * CRC is added for AU for EzGET.
656    */
657   if (spec->html_spec_type == CHXJ_SPEC_XHtml_Mobile_1_0
658   ||  spec->html_spec_type == CHXJ_SPEC_Hdml            ) {
659
660     crc = s_add_crc(writedata, writebyte);
661
662     rv = apr_file_putc((crc >> 8)  & 0xff, fout);
663     if (rv != APR_SUCCESS) {
664       DestroyMagickWand(magick_wand);
665       return HTTP_INTERNAL_SERVER_ERROR;
666     }
667
668     rv = apr_file_putc( crc        & 0xff, fout);
669     if (rv != APR_SUCCESS) {
670       DestroyMagickWand(magick_wand);
671       return HTTP_INTERNAL_SERVER_ERROR;
672     }
673   }
674
675   DestroyMagickWand(magick_wand);
676
677   rv = apr_file_close(fout);
678   if (rv != APR_SUCCESS) {
679     DBG1(r,"file write error.[%s]", tmpfile);
680     return HTTP_INTERNAL_SERVER_ERROR;
681   }
682
683   return OK;
684 }
685
686
687 static char*
688 s_create_blob_data(request_rec* r, 
689                    device_table* spec, 
690                    query_string_param_t *qsp,
691                    char* indata,
692                    apr_size_t* len)
693 {
694   apr_size_t         writebyte;
695   unsigned short     crc;
696   img_conv_mode_t    mode = qsp->mode;
697
698   char*              writedata = NULL;
699   char*              dst       = NULL;
700
701   MagickWand*        magick_wand;
702
703   magick_wand = NewMagickWand();
704
705   if (MagickReadImageBlob(magick_wand,indata, *len) == MagickFalse) {
706     EXIT_MAGICK_ERROR();
707     return NULL;
708   }
709
710   /*
711    * The size of the image is changed.
712    */
713   DBG(r, "call s_fixup_size()");
714
715   if ((magick_wand = s_fixup_size(magick_wand, r, spec, qsp)) == NULL)
716     return NULL;
717
718   /*
719    * The colors of the image is changed.
720    */
721   DBG(r, "call s_fixup_color()");
722
723   if ((magick_wand = s_fixup_color(magick_wand, r,spec, mode)) == NULL)
724     return NULL;
725
726   /*
727    * DEPTH of the image is changed.
728    */
729
730   DBG(r,"call s_fixup_depth()");
731
732   if ((magick_wand = s_fixup_depth(magick_wand, r, spec)) == NULL)
733     return NULL;
734
735
736
737   DBG(r,"start convert and compression");
738
739   if (spec->available_jpeg) {
740     if (MagickSetImageCompression(magick_wand,JPEGCompression) == MagickFalse) {
741       EXIT_MAGICK_ERROR();
742       return NULL;
743     }
744
745     if (MagickSetImageFormat(magick_wand, "jpg") == MagickFalse) {
746       EXIT_MAGICK_ERROR();
747       return NULL;
748     }
749
750     if (MagickStripImage(magick_wand) == MagickFalse) {
751       EXIT_MAGICK_ERROR();
752       return NULL;
753     }
754
755     if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL)
756       return NULL;
757
758     r->content_type = apr_psprintf(r->pool, "image/jpeg");
759
760     DBG(r, "convert to jpg");
761   }
762   else
763   if (spec->available_png) {
764     if (MagickSetImageCompression(magick_wand,ZipCompression) == MagickFalse) {
765       EXIT_MAGICK_ERROR();
766       return NULL;
767     }
768
769     if (MagickSetImageFormat(magick_wand, "png") == MagickFalse) {
770       EXIT_MAGICK_ERROR();
771       return NULL;
772     }
773
774     if (MagickStripImage(magick_wand) == MagickFalse) {
775       EXIT_MAGICK_ERROR();
776       return NULL;
777     }
778
779     if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL)
780       return NULL;
781
782     r->content_type = apr_psprintf(r->pool, "image/png");
783
784     DBG(r,"convert to png");
785   }
786   else
787   if (spec->available_gif) {
788
789     if (MagickSetImageCompression(magick_wand,LZWCompression) == MagickFalse) {
790       EXIT_MAGICK_ERROR();
791       return NULL;
792     }
793
794     if (MagickSetImageFormat(magick_wand, "gif") == MagickFalse) {
795       EXIT_MAGICK_ERROR();
796       return NULL;
797     }
798
799     if (MagickStripImage(magick_wand) == MagickFalse) {
800       EXIT_MAGICK_ERROR();
801       return NULL;
802     }
803
804     if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL)
805       return NULL;
806
807     r->content_type = apr_psprintf(r->pool, "image/gif");
808
809     DBG(r,"convert to gif");
810   }
811   else
812   if (spec->available_bmp2 || spec->available_bmp4) {
813     if (MagickSetImageCompression(magick_wand,NoCompression) == MagickFalse) {
814       EXIT_MAGICK_ERROR();
815       return NULL;
816     }
817
818     if (MagickSetImageFormat(magick_wand, "bmp") == MagickFalse) {
819       EXIT_MAGICK_ERROR();
820       return NULL;
821     }
822
823     if (MagickStripImage(magick_wand) == MagickFalse) {
824       EXIT_MAGICK_ERROR();
825       return NULL;
826     }
827
828     if ((magick_wand = s_img_down_sizing(magick_wand, r, spec)) == NULL)
829       return NULL;
830
831     r->content_type = apr_psprintf(r->pool, "image/bmp");
832
833     DBG(r,"convert to bmp(unsupported)");
834   }
835   /*--------------------------------------------------------------------------*/
836   /* Add Comment (Copyright and so on.)                                       */
837   /*--------------------------------------------------------------------------*/
838   DBG(r,"call s_add_copyright()");
839
840   if ((magick_wand = s_add_copyright(magick_wand, r, spec)) == NULL)
841     return NULL;
842
843   writedata = (char*)MagickGetImageBlob(magick_wand, &writebyte);
844
845   if (! writebyte) {
846     DestroyMagickWand(magick_wand);
847     DBG(r,"convert failure to Jpeg ");
848     return NULL;
849   }
850
851   DBG(r,"end convert and compression");
852
853
854   
855   dst = apr_palloc(r->pool, writebyte+2);
856
857   memcpy(dst, writedata, writebyte);
858   /*--------------------------------------------------------------------------*/
859   /* CRC is added for AU for EzGET.                                           */
860   /*--------------------------------------------------------------------------*/
861   if (spec->html_spec_type == CHXJ_SPEC_XHtml_Mobile_1_0
862   ||  spec->html_spec_type == CHXJ_SPEC_Hdml) {
863     crc = s_add_crc(writedata, writebyte);
864     dst[writebyte + 0] = (crc >> 8) & 0xff;
865     dst[writebyte + 1] = (crc     ) & 0xff;
866     writebyte += 2;
867   }
868
869   DestroyMagickWand(magick_wand);
870
871   *len = writebyte;
872   return dst;
873 }
874
875 static MagickWand* 
876 s_fixup_size(MagickWand* magick_wand, 
877                 request_rec* r, 
878                 device_table* spec, 
879                 query_string_param_t *qsp)
880 {
881   img_conv_mode_t mode = qsp->mode;
882   int oldw;
883   int oldh;
884   int neww;
885   int newh;
886   int c_width;
887   int c_heigh;
888
889   oldw = MagickGetImageWidth(magick_wand);
890   oldh = MagickGetImageHeight(magick_wand);
891
892   DBG1(r,"detect width=[%d]", oldw);
893   DBG1(r,"detect heigh=[%d]", oldh);
894
895   neww = oldw;
896   newh = oldh;
897
898   DBG1(r,"detect spec width=[%d]", spec->width);
899   DBG1(r,"detect spec heigh=[%d]", spec->heigh);
900
901   c_width = spec->width;
902   c_heigh = spec->heigh;
903
904   switch(mode) {
905   case IMG_CONV_MODE_THUMBNAIL:
906
907     DBG(r,"**** detect thumbnail mode ****");
908
909     if (neww > c_width) {
910       newh = (int)((double)newh * (double)((double)c_width / (double)neww));
911       neww = (int)((double)neww * (double)((double)c_width / (double)neww));
912     }
913     if (newh > c_heigh) {
914       neww = (int)((double)neww * (double)((double)c_heigh / (double)newh));
915       newh = (int)((double)newh * (double)((double)c_heigh / (double)newh));
916     }
917
918     neww = (int)((double)(neww / 3) * 0.8);
919     newh = (int)((double)(newh / 3) * 0.8);
920     break;
921
922   case IMG_CONV_MODE_WALLPAPER:
923   case IMG_CONV_MODE_EZGET:
924
925     DBG(r,"**** detect wallpaper mode ****");
926
927     if (spec->wp_width && spec->wp_heigh) {
928       c_width = spec->wp_width;
929       c_heigh = spec->wp_heigh;
930     }
931
932     DBG(r,"calc new width and height");
933
934     neww = (int)((double)neww * (double)((double)c_heigh / (double)newh));
935     newh = (int)((double)newh * (double)((double)c_heigh / (double)newh));
936
937     DBG2(r,"newh = [%d] neww = [%d]", newh, neww);
938     break;
939
940   default:
941
942     DBG(r,"**** detect normal mode ****");
943
944     if (qsp->ua_flag != UA_IGN) {
945       if (neww > c_width) {
946         newh = (int)((double)newh * (double)((double)c_width / (double)neww));
947         neww = (int)((double)neww * (double)((double)c_width / (double)neww));
948       }
949
950       if (newh > c_heigh) {
951         neww = (int)((double)neww * (double)((double)c_heigh / (double)newh));
952         newh = (int)((double)newh * (double)((double)c_heigh / (double)newh));
953       }
954     }
955     break;
956   }
957
958   DBG2(r,"convert width=[%d --> %d]", oldw, neww);
959   DBG2(r,"convert heigh=[%d --> %d]", oldh, newh);
960
961   MagickResetIterator(magick_wand);
962
963   while (MagickNextImage(magick_wand) != MagickFalse) {
964     switch (mode) {
965     case IMG_CONV_MODE_WALLPAPER:
966     case IMG_CONV_MODE_EZGET:
967
968       if (MagickResizeImage(magick_wand,neww,newh,LanczosFilter,1.0) == MagickFalse) {
969         EXIT_MAGICK_ERROR();
970         return NULL;
971       }
972
973       if (MagickCropImage(magick_wand, 
974                       (unsigned long)c_width, 
975                       (unsigned long)c_heigh,
976                       (long)((neww - c_width) / 2),
977                       (long)((newh - c_heigh) / 2)) == MagickFalse) {
978         EXIT_MAGICK_ERROR();
979         return NULL;
980       }
981       break;
982
983     case IMG_CONV_MODE_NORMAL:
984       if (qsp->width) {
985         DBG2(r,"convert width=[%d --> %d]", neww, qsp->width);
986         neww = qsp->width;
987       }
988       if (qsp->height) {
989         DBG2(r,"convert heigh=[%d --> %d]", newh, qsp->height);
990         newh = qsp->height;
991       }
992
993     default:
994       if (MagickResizeImage(magick_wand,neww,newh,LanczosFilter,1.0) == MagickFalse) {
995         EXIT_MAGICK_ERROR();
996         return NULL;
997       }
998       break;
999     }
1000
1001     if (MagickSetImageUnits(magick_wand, PixelsPerInchResolution) == MagickFalse) {
1002       EXIT_MAGICK_ERROR();
1003       return NULL;
1004     }
1005
1006     if (MagickSetImageResolution(magick_wand,
1007                                  (double)spec->dpi_width,
1008                                  (double)spec->dpi_heigh) == MagickFalse) {
1009       EXIT_MAGICK_ERROR();
1010       return NULL;
1011     }
1012
1013     if (MagickSetImageDispose(magick_wand, BackgroundDispose) == MagickFalse) {
1014       EXIT_MAGICK_ERROR();
1015       return NULL;
1016     }
1017   }
1018
1019   return magick_wand;
1020 }
1021
1022 static MagickWand*
1023 s_fixup_color(MagickWand* magick_wand, request_rec* r, device_table* spec, img_conv_mode_t mode)
1024 {
1025   DBG(r,"start chxj_fixup_clor()");
1026
1027   if (spec->color >= 256) {
1028
1029     DBG1(r,"call MagickQuantizeImage() spec->color=[%d]",spec->color);
1030
1031     if (MagickQuantizeImage(magick_wand,
1032                            spec->color,
1033                            RGBColorspace,
1034                            0,
1035                            1,
1036                            0) == MagickFalse) {
1037       EXIT_MAGICK_ERROR();
1038       return NULL;
1039     }
1040
1041     DBG1(r,"call end MagickQuantizeImage() spec->color=[%d]",spec->color);
1042
1043   }
1044   else {
1045     DBG1(r,"call MagickQuantizeImage() spec->color=[%d]",spec->color);
1046
1047     if (MagickQuantizeImage(magick_wand,
1048                            spec->color,
1049                            GRAYColorspace,
1050                            0,
1051                            1,
1052                            0) == MagickFalse) {
1053       EXIT_MAGICK_ERROR();
1054       return NULL;
1055     }
1056
1057     DBG1(r,"call end MagickQuantizeImage() spec->color=[%d]",spec->color);
1058   }
1059
1060
1061   DBG(r,"end chxj_fixup_clor()");
1062
1063   return magick_wand;
1064 }
1065
1066
1067
1068 static MagickWand*
1069 s_fixup_depth(MagickWand* magick_wand, request_rec* r, device_table* spec)
1070 {
1071   if (spec->color == 15680000) {
1072     if (MagickSetImageDepth(magick_wand, 24) == MagickFalse) {
1073       EXIT_MAGICK_ERROR();
1074       return NULL;
1075     }
1076   }
1077   else 
1078   if (spec->color == 262144) {
1079     if (MagickSetImageDepth(magick_wand, 18) == MagickFalse) {
1080       EXIT_MAGICK_ERROR();
1081       return NULL;
1082     }
1083   }
1084   else
1085   if (spec->color == 65536) {
1086     if (MagickSetImageDepth(magick_wand, 16) == MagickFalse) {
1087       EXIT_MAGICK_ERROR();
1088       return NULL;
1089     }
1090   }
1091   else
1092   if (spec->color == 4096) {
1093     if (MagickSetImageDepth(magick_wand, 12) == MagickFalse) {
1094       EXIT_MAGICK_ERROR();
1095       return NULL;
1096     }
1097   }
1098   else
1099   if (spec->color == 256) {
1100     if (MagickSetImageDepth(magick_wand, 8) == MagickFalse) {
1101       EXIT_MAGICK_ERROR();
1102       return NULL;
1103     }
1104   }
1105   else
1106   if (spec->color == 4) {
1107     if (MagickSetImageDepth(magick_wand, 2) == MagickFalse) {
1108       EXIT_MAGICK_ERROR();
1109       return NULL;
1110     }
1111   }
1112   else
1113   if (spec->color == 2) {
1114     if (MagickSetImageDepth(magick_wand, 1) == MagickFalse) {
1115       EXIT_MAGICK_ERROR();
1116       return NULL;
1117     }
1118   }
1119
1120   return magick_wand;
1121 }
1122
1123
1124 static MagickWand*
1125 s_add_copyright(MagickWand* magick_wand, request_rec* r, device_table* spec)
1126 {
1127   mod_chxj_config* conf = ap_get_module_config(r->per_dir_config, &chxj_module);
1128
1129   if (conf->image_copyright) {
1130
1131     DBG1(r, "Add COPYRIGHT [%s]", conf->image_copyright);
1132
1133     if (spec->html_spec_type == CHXJ_SPEC_Jhtml) {
1134       apr_table_setn(r->headers_out, "x-jphone-copyright", "no-transfer");
1135       if (MagickCommentImage(magick_wand, 
1136                              apr_psprintf(r->pool, 
1137                                           "Copyright(C) %s", 
1138                                           conf->image_copyright)) == MagickFalse) 
1139         goto on_error;
1140     }
1141     else
1142     if (spec->html_spec_type == CHXJ_SPEC_XHtml_Mobile_1_0
1143     ||  spec->html_spec_type == CHXJ_SPEC_Hdml) {
1144       if (MagickCommentImage(magick_wand, 
1145                              apr_psprintf(r->pool, 
1146                                          "kddi_copyright=on,%s", 
1147                                           conf->image_copyright)) == MagickFalse) 
1148         goto on_error;
1149     }
1150     else {
1151       if (MagickCommentImage(magick_wand, 
1152                             apr_psprintf(r->pool, 
1153                                          "copy=\"NO\",%s",
1154                                          conf->image_copyright)) == MagickFalse)
1155         goto on_error;
1156     }
1157   }
1158   else {
1159     if (MagickCommentImage(magick_wand, "mod_chxj") == MagickFalse)
1160       goto on_error;
1161   }
1162   return magick_wand;
1163
1164 on_error:
1165   EXIT_MAGICK_ERROR();
1166   return NULL;
1167 }
1168
1169 static MagickWand*
1170 s_img_down_sizing(MagickWand* magick_wand, request_rec* r, device_table* spec)
1171 {
1172   MagickBooleanType  status;
1173   unsigned long quality = 70;
1174   apr_size_t    writebyte = 0;
1175   char*         writedata;
1176   apr_size_t    prev_size = 0;
1177   int           revers_flag = 0;
1178
1179   writedata = (char*)MagickGetImageBlob(magick_wand, &writebyte);
1180   prev_size = writebyte;
1181
1182   do {
1183     if (MagickSetImageCompressionQuality(magick_wand, quality) == MagickFalse) {
1184       EXIT_MAGICK_ERROR();
1185       return NULL;
1186     }
1187
1188     writedata = (char*)MagickGetImageBlob(magick_wand, &writebyte);
1189     if (writebyte >= prev_size || revers_flag) {
1190       DBG2(r, "quality=[%ld] size=[%d]", (long)quality, writebyte);
1191       revers_flag = 1;
1192       quality += 10;
1193       if (quality > 100) {
1194         if (MagickSetImageCompression(magick_wand,NoCompression) == MagickFalse) {
1195           EXIT_MAGICK_ERROR();
1196           return NULL;
1197         }
1198         break;
1199       }
1200       prev_size = writebyte;
1201       continue;
1202     }
1203
1204     DBG2(r, "quality=[%ld] size=[%d]", (long)quality, writebyte);
1205
1206     if (spec->cache == 0)
1207       break;
1208
1209     if (writebyte <= spec->cache)
1210       break;
1211
1212     quality -= 10;
1213
1214     if (quality == 0 || quality > 100)
1215       break;
1216
1217   }
1218   while (1);
1219
1220
1221   if (spec->cache > 0 
1222   &&  writebyte   > spec->cache) {
1223     unsigned long now_color = spec->color;
1224     unsigned long depth     = 0;
1225     do {
1226       switch(now_color) {
1227       case 2:      depth = 1; break;
1228       case 4:      now_color = 2;        depth = 1;  break;
1229       case 8:      now_color = 4;        depth = 2;  break;
1230       case 16:     now_color = 8;        depth = 3;  break;
1231       case 256:    now_color = 16;       depth = 4;  break;
1232       case 4096:   now_color = 256;      depth = 8;  break;
1233       case 65536:  now_color = 4096;     depth = 12; break;
1234       case 262144: now_color = 65536;    depth = 16; break;
1235       case 15680000: now_color = 262144; depth = 18; break;
1236       default:
1237         now_color = 2;
1238         break;
1239       }
1240
1241       if (now_color <= 2) break;
1242
1243       if (now_color >= 8) {
1244         status = MagickQuantizeImage(magick_wand,
1245                              now_color,
1246                              RGBColorspace,
1247                              0,
1248                              1,
1249                              0);
1250       }
1251       else {
1252         status = MagickQuantizeImage(magick_wand,
1253                              now_color,
1254                              GRAYColorspace,
1255                              0,
1256                              1,
1257                              0);
1258         MagickSetImageType(magick_wand, GrayscaleType);
1259       }
1260       if (status == MagickFalse) {
1261         EXIT_MAGICK_ERROR();
1262         return NULL;
1263       }
1264
1265       if (MagickSetImageDepth(magick_wand, depth) == MagickFalse) {
1266         EXIT_MAGICK_ERROR();
1267         return NULL;
1268       }
1269
1270       writedata = (char*)MagickGetImageBlob(magick_wand, &writebyte);
1271
1272       DBG2(r,"now_color=[%ld] size=[%d]", (long)now_color, writebyte);
1273
1274       /* Once per request */
1275       break;
1276     }
1277     while(now_color > 2);
1278   }
1279
1280   return magick_wand;
1281 }
1282
1283 static apr_status_t 
1284 s_send_cache_file(device_table* spec, query_string_param_t* query_string, request_rec* r, const char* tmpfile)
1285 {
1286   apr_status_t rv;
1287   apr_finfo_t  st;
1288   apr_file_t*  fout;
1289   apr_size_t   sendbyte;
1290   char*        contentLength;
1291
1292   rv = apr_stat(&st, tmpfile, APR_FINFO_MIN, r->pool);
1293   if (rv != APR_SUCCESS)
1294     return HTTP_NOT_FOUND;
1295
1296   DBG1(r, "mode:[%d]",    query_string->mode);
1297   DBG1(r, "name:[%s]",    query_string->name);
1298   DBG1(r, "offset:[%ld]", query_string->offset);
1299   DBG1(r, "count:[%ld]",  query_string->count);
1300
1301   if (spec->available_jpeg) {
1302     r->content_type = apr_psprintf(r->pool, "image/jpeg");
1303   }
1304   else
1305   if (spec->available_png) {
1306     r->content_type = apr_psprintf(r->pool, "image/png");
1307   }
1308   else
1309   if (spec->available_gif) {
1310     r->content_type = apr_psprintf(r->pool, "image/gif");
1311   }
1312   else
1313   if (spec->available_bmp2 || spec->available_bmp4) {
1314     r->content_type = apr_psprintf(r->pool, "image/bmp");
1315   }
1316
1317   if (query_string->mode != IMG_CONV_MODE_EZGET && query_string->name == NULL) {
1318     contentLength = apr_psprintf(r->pool, "%d", (int)st.size);
1319     apr_table_setn(r->headers_out, "Content-Length", (const char*)contentLength);
1320   
1321     DBG1(r,"Content-Length:[%d]", (int)st.size);
1322
1323     rv = apr_file_open(&fout, tmpfile, 
1324       APR_READ | APR_BINARY, APR_OS_DEFAULT, r->pool);
1325     if (rv != APR_SUCCESS) {
1326       DBG1(r, "tmpfile open failed[%s]", tmpfile);
1327       return HTTP_NOT_FOUND;
1328     }
1329
1330     ap_send_fd(fout, r, 0, st.size, &sendbyte);
1331     apr_file_close(fout);
1332     ap_rflush(r);
1333     DBG1(r, "send file data[%d]byte", sendbyte);
1334   }
1335   else
1336   if (query_string->mode == IMG_CONV_MODE_EZGET) {
1337     char* name = apr_pstrdup(r->pool, basename(r->filename));
1338     name[strlen(name)-4] = 0;
1339     if (strcasecmp(r->content_type, "image/jpeg") == 0) {
1340
1341       ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
1342       ap_rprintf(r, HDML_FIRST_PAGE, r->uri, name, ".jpg", (long)st.size, "devjaww", name);
1343     }
1344     else
1345     if (strcasecmp(r->content_type, "image/bmp") == 0) {
1346       ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
1347       ap_rprintf(r, HDML_FIRST_PAGE, r->uri, name, ".bmp", (long)st.size, "devabm", name);
1348     }
1349     else
1350     if (strcasecmp(r->content_type, "image/png") == 0) {
1351       ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
1352       ap_rprintf(r, HDML_FIRST_PAGE, r->uri, name, ".png", (long)st.size, "dev8aww", name);
1353     }
1354     else
1355     if (strcasecmp(r->content_type, "image/gif") == 0) {
1356       ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
1357       ap_rprintf(r, HDML_FIRST_PAGE, r->uri, name, ".gif", (long)st.size, "devgi0z", name);
1358     }
1359   }
1360   else
1361   if (query_string->mode == IMG_CONV_MODE_WALLPAPER && query_string->name != NULL) {
1362     if (query_string->count == -1 && query_string->offset == -1) {
1363       ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
1364       ap_rprintf(r, HDML_SUCCESS_PAGE);
1365       ap_rflush(r);
1366     }
1367     else
1368     if (query_string->count == -2 && query_string->offset == -1) {
1369       ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
1370       ap_rprintf(r, HDML_FAIL_PAGE);
1371       ap_rflush(r);
1372     }
1373     else { 
1374       ap_set_content_type(r, "application/x-up-download");
1375       contentLength = apr_psprintf(r->pool, "%ld", query_string->count);
1376       apr_table_setn(r->headers_out, "Content-Length", (const char*)contentLength);
1377   
1378       DBG1(r, "Content-Length:[%d]", (int)st.size);
1379
1380       rv = apr_file_open(&fout, tmpfile, 
1381         APR_READ | APR_BINARY, APR_OS_DEFAULT, r->pool);
1382
1383       if (rv != APR_SUCCESS) {
1384         DBG1(r,"tmpfile open failed[%s]", tmpfile);
1385         return HTTP_NOT_FOUND;
1386       }
1387
1388       ap_send_fd(fout, r, query_string->offset, query_string->count, &sendbyte);
1389       apr_file_close(fout);
1390       ap_rflush(r);
1391       DBG1(r, "send file data[%d]byte", sendbyte);
1392     }
1393   }
1394   
1395   return OK;
1396 }
1397
1398 static apr_status_t 
1399 s_header_only_cache_file(device_table* spec, query_string_param_t* query_string, request_rec* r, const char* tmpfile)
1400 {
1401   apr_status_t rv;
1402   apr_finfo_t  st;
1403   char*        contentLength;
1404
1405   rv = apr_stat(&st, tmpfile, APR_FINFO_MIN, r->pool);
1406   if (rv != APR_SUCCESS)
1407     return HTTP_NOT_FOUND;
1408
1409   DBG1(r, "mode:[%d]",    query_string->mode);
1410   DBG1(r, "name:[%s]",    query_string->name);
1411   DBG1(r, "offset:[%ld]", query_string->offset);
1412   DBG1(r, "count:[%ld]",  query_string->count);
1413
1414   if (spec->available_jpeg) {
1415     r->content_type = apr_psprintf(r->pool, "image/jpeg");
1416   }
1417   else
1418   if (spec->available_png) {
1419     r->content_type = apr_psprintf(r->pool, "image/png");
1420   }
1421   else
1422   if (spec->available_gif) {
1423     r->content_type = apr_psprintf(r->pool, "image/gif");
1424   }
1425   else
1426   if (spec->available_bmp2 || spec->available_bmp4) {
1427     r->content_type = apr_psprintf(r->pool, "image/bmp");
1428   }
1429
1430   if (query_string->mode != IMG_CONV_MODE_EZGET && query_string->name == NULL) {
1431     contentLength = apr_psprintf(r->pool, "%d", (int)st.size);
1432     apr_table_setn(r->headers_out, "Content-Length", (const char*)contentLength);
1433   
1434     DBG1(r,"Content-Length:[%d]", (int)st.size);
1435   }
1436   else
1437   if (query_string->mode == IMG_CONV_MODE_EZGET) {
1438     char* name = apr_pstrdup(r->pool, basename(r->filename));
1439     name[strlen(name)-4] = 0;
1440     if (strcasecmp(r->content_type, "image/jpeg") == 0) {
1441
1442       ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
1443     }
1444     else
1445     if (strcasecmp(r->content_type, "image/bmp") == 0) {
1446       ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
1447     }
1448     else
1449     if (strcasecmp(r->content_type, "image/png") == 0) {
1450       ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
1451     }
1452     else
1453     if (strcasecmp(r->content_type, "image/gif") == 0) {
1454       ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
1455     }
1456   }
1457   else
1458   if (query_string->mode == IMG_CONV_MODE_WALLPAPER && query_string->name != NULL) {
1459     if (query_string->count == -1 && query_string->offset == -1) {
1460       ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
1461     }
1462     else
1463     if (query_string->count == -2 && query_string->offset == -1) {
1464       ap_set_content_type(r, "text/x-hdml; charset=Shift_JIS");
1465     }
1466     else { 
1467       ap_set_content_type(r, "application/x-up-download");
1468       contentLength = apr_psprintf(r->pool, "%ld", query_string->count);
1469       apr_table_setn(r->headers_out, "Content-Length", (const char*)contentLength);
1470   
1471       DBG1(r, "Content-Length:[%d]", (int)st.size);
1472     }
1473   }
1474   
1475   return OK;
1476 }
1477
1478
1479
1480 static char*
1481 s_create_workfile(
1482                 request_rec*          r, 
1483                 mod_chxj_config*      conf, 
1484                 const char*           user_agent, 
1485                 query_string_param_t *qsp)
1486 {
1487   int ii;
1488   int jj;
1489   int len;
1490   char* w = apr_palloc(r->pool, 256);
1491   char* fname;
1492
1493   memset(w, 0, 256);
1494   switch (qsp->mode) {
1495   case IMG_CONV_MODE_THUMBNAIL:
1496     fname = apr_psprintf(r->pool, "%s.%s.thumbnail", r->filename, user_agent);
1497     DBG1(r, "mode=thumbnail [%s]", fname);
1498     break;
1499   case IMG_CONV_MODE_WALLPAPER:
1500   case IMG_CONV_MODE_EZGET:
1501     fname = apr_psprintf(r->pool, "%s.%s.wallpaper", r->filename, user_agent);
1502     DBG1(r, "mode=WallPaper [%s]", fname);
1503     break;
1504   case IMG_CONV_MODE_NORMAL:
1505   default:
1506
1507     fname = apr_psprintf(r->pool, "%s.%s", r->filename, user_agent);
1508
1509     if (qsp->width)
1510       fname = apr_psprintf(r->pool, "%s.w%d", fname, qsp->width);
1511
1512     if (qsp->height)
1513       fname = apr_psprintf(r->pool, "%s.h%d", fname, qsp->height);
1514
1515     DBG1(r,"mode=normal [%s]", fname);
1516     break;
1517   }
1518   if (qsp->ua_flag == UA_IGN) {
1519     fname = apr_psprintf(r->pool, "%s.IGN", fname);
1520   }
1521
1522   len = strlen(fname);
1523   jj=0;
1524   for  (ii=0; ii<len; ii++) {
1525     if (fname[ii] == '/' 
1526     ||  fname[ii] == ' ' 
1527     ||  fname[ii] == '-' 
1528     ||  fname[ii] == '(' 
1529     ||  fname[ii] == ')') {
1530       w[jj++] = '_';
1531     }
1532     else {
1533       w[jj++] = fname[ii];
1534     }
1535   }
1536
1537   return apr_psprintf(r->pool, "%s/%s", conf->image_cache_dir,w);
1538 }
1539
1540 static unsigned short
1541 s_add_crc(const char* writedata, apr_size_t writebyte)
1542 {
1543   unsigned short crc = 0xffff;
1544   apr_size_t     ii;
1545   unsigned char  ch;
1546
1547   for(ii=0;ii<writebyte;ii++) {
1548     ch  = writedata[ii];
1549     crc = AU_CRC_TBL[(crc>>8^ch)&0xff]^(crc<<8);
1550   }
1551   return crc;
1552 }
1553
1554 int
1555 chxj_trans_name(request_rec *r)
1556 {
1557   const char* ccp;
1558   char* docroot;
1559   int len;
1560   apr_finfo_t st;
1561   apr_status_t rv;
1562   mod_chxj_config* conf;
1563   int ii;
1564   char*      ext[] = {
1565           "jpg",
1566           "jpeg",
1567           "png",
1568           "bmp",
1569           "gif",
1570           "qrc",    /* QRCode½ÐÎÏÍÑ¥Õ¥¡¥¤¥ë¤Î³ÈÄ¥»Ò */
1571           "",
1572   };
1573   char*    fname;
1574   char*    idx;
1575   char*    filename_sv;
1576   int      do_ext_check = TRUE;
1577   int      next_ok      = FALSE;
1578
1579   DBG(r, "start chxj_trans_name()");
1580
1581   conf = ap_get_module_config(r->per_dir_config, &chxj_module);
1582
1583   if (conf == NULL) {
1584     DBG1(r, "end chxj_trans_name() conf is null[%s]", r->uri);
1585     return DECLINED;
1586   }
1587
1588   if (conf->image != CHXJ_IMG_ON) {
1589     DBG(r, "end chxj_trans_name() conf not found");
1590     return DECLINED;
1591   }
1592
1593
1594   DBG1(r,"Match URI[%s]", r->uri);
1595
1596
1597   if (r->filename == NULL) 
1598     r->filename = apr_pstrdup(r->pool, r->uri);
1599
1600   filename_sv = NULL;
1601   if ((idx = strchr(r->filename, ':')) != NULL) 
1602     filename_sv = idx+1;
1603   else 
1604     filename_sv = r->filename;
1605
1606   DBG1(r,"r->filename[%s]", filename_sv);
1607
1608   ccp = ap_document_root(r);
1609   if (ccp == NULL)
1610     return HTTP_INTERNAL_SERVER_ERROR;
1611
1612   docroot = apr_pstrdup(r->pool, ccp);
1613   len = strlen(docroot);
1614
1615   if (docroot[len-1] == '/') 
1616     docroot[len-1] = '\0';
1617
1618
1619   if (r->server->path 
1620   &&  *filename_sv == *r->server->path 
1621   &&  strncmp(filename_sv, r->server->path, r->server->pathlen) == 0)
1622     filename_sv = apr_pstrcat(r->pool, docroot, (filename_sv + r->server->pathlen), NULL);
1623   else
1624     filename_sv = apr_pstrcat(r->pool, docroot, filename_sv, NULL);
1625
1626   DBG1(r,"URI[%s]", filename_sv);
1627
1628   do_ext_check = TRUE;
1629   for (ii=0; ii<7-1; ii++) {
1630     char* pos = strrchr(filename_sv, '.');
1631     if (pos && pos++) {
1632       if (strcasecmp(pos, ext[ii]) == 0) {
1633         do_ext_check = FALSE;
1634         fname = apr_psprintf(r->pool, "%s", filename_sv);
1635         break;
1636       }
1637     }
1638   }
1639
1640   if (do_ext_check) {
1641     for (ii=0; ii<7; ii++) {
1642       if (strlen(ext[ii]) == 0) {
1643         fname = apr_psprintf(r->pool, "%s", filename_sv);
1644       }
1645       else 
1646         fname = apr_psprintf(r->pool, "%s.%s", filename_sv, ext[ii]);
1647   
1648       DBG1(r,"search [%s]", fname);
1649   
1650       rv = apr_stat(&st, fname, APR_FINFO_MIN, r->pool);
1651       if (rv == APR_SUCCESS) {
1652         if (st.filetype != APR_DIR)
1653           break;
1654       }
1655   
1656       fname = NULL;
1657     }
1658   }
1659   if (fname == NULL) {
1660     DBG1(r,"NotFound [%s]", r->filename);
1661     return DECLINED;
1662   }
1663   for (ii=0; ii<7-1; ii++) {
1664     char* pos = strrchr(fname, '.');
1665     if (pos && pos++) {
1666       if (strcasecmp(pos, ext[ii]) == 0) {
1667         next_ok = TRUE;
1668         break;
1669       }
1670     }
1671   }
1672
1673   if (! next_ok)  {
1674     DBG1(r,"NotFound [%s]", r->filename);
1675     return DECLINED;
1676   }
1677
1678   if (r->handler == NULL || strcasecmp(r->handler, "chxj-qrcode") != 0) {
1679     DBG1(r,"Found [%s]", fname);
1680
1681     r->filename = apr_psprintf(r->pool, "%s", fname);
1682   
1683     if (strcasecmp("qrc", ext[ii]) == 0)
1684       r->handler = apr_psprintf(r->pool, "chxj-qrcode");
1685     else
1686       r->handler = apr_psprintf(r->pool, "chxj-picture");
1687   }
1688   DBG(r, "end chxj_trans_name()");
1689   return OK;
1690 }
1691
1692
1693
1694 /**
1695  * It converts it from QUERYSTRING.
1696  *
1697  * @param r   [i]
1698  */
1699 static query_string_param_t*
1700 s_get_query_string_param(request_rec *r)
1701 {
1702   char* pair;
1703   char* name;
1704   char* value;
1705   char* pstate;
1706   char* vstate;
1707   char* s;
1708   query_string_param_t* param;
1709
1710   s = apr_pstrdup(r->pool, r->parsed_uri.query);
1711   param = apr_palloc(r->pool, sizeof(query_string_param_t));
1712   param->mode       = IMG_CONV_MODE_NORMAL;
1713   param->user_agent = NULL;
1714   param->ua_flag    = UA_USE;
1715   param->name       = NULL;
1716   param->offset     = 0;
1717   param->count      = 0;
1718   param->width      = 0;
1719   param->height     = 0;
1720
1721   if (s == NULL) return param;
1722
1723   for (;;) {
1724     if ((pair = apr_strtok(s, "&", &pstate)) == NULL) break;
1725     s = NULL;
1726
1727     name  = apr_strtok(pair, "=", &vstate);
1728     value = apr_strtok(NULL, "=", &vstate);
1729
1730     switch (*name) {
1731     case 'm':
1732     case 'M':
1733       if (value && (strcasecmp(name, "mode") == 0 || strcasecmp(name, "m") == 0)) {
1734
1735         switch (*value) {
1736         case 't':
1737         case 'T':
1738           if (strcasecmp(value, "thumbnail") == 0 || strcasecmp(value, "tb") == 0)
1739             param->mode = IMG_CONV_MODE_THUMBNAIL;
1740           break;
1741   
1742         case 'w':
1743         case 'W':
1744           if (strcasecmp(value, "WP") == 0 || strcasecmp(value, "WallPaper") == 0)
1745             param->mode = IMG_CONV_MODE_WALLPAPER;
1746           break;
1747   
1748         case 'e':
1749         case 'E':
1750           if (strcasecmp(value, "EZGET") == 0)
1751             param->mode = IMG_CONV_MODE_EZGET;
1752           break;
1753         default:
1754           break;
1755         }
1756       }
1757       break;
1758
1759     case 'u':
1760     case 'U':
1761       if (value && (strcasecmp(name, "ua") == 0 || strcasecmp(name, "user-agent") == 0)) {
1762         ap_unescape_url(value);
1763
1764         if ((*value == 'i' || *value == 'I') && strcasecmp(value, "IGN") == 0)
1765           param->ua_flag = UA_IGN;
1766
1767         param->user_agent = apr_pstrdup(r->pool, value);
1768       }
1769       break;
1770
1771     case 'n':
1772     case 'N':
1773       if (value && strcasecmp(name, "name") == 0)
1774         param->name = apr_pstrdup(r->pool, value);
1775       break;
1776
1777     case 'o':
1778     case 'O':
1779       if (value && strcasecmp(name, "offset") == 0 && (! chxj_chk_numeric(value)))
1780         param->offset = chxj_atoi(value);
1781
1782       break;
1783
1784     case 'c':
1785     case 'C':
1786       if (value && strcasecmp(name, "count") == 0 && (! chxj_chk_numeric(value)))
1787         param->count = chxj_atoi(value);
1788       break;
1789
1790     case 'w':
1791     case 'W':
1792       if (value && strcasecmp(name, "w") == 0 && (! chxj_chk_numeric(value)))
1793         param->width = chxj_atoi(value);
1794       break;
1795
1796     case 'h':
1797     case 'H':
1798       if (value && strcasecmp(name, "h") == 0 && (! chxj_chk_numeric(value)))
1799         param->height = chxj_atoi(value);
1800       break;
1801
1802     default:
1803       break;
1804     }
1805   }
1806
1807   if (param->mode == IMG_CONV_MODE_NORMAL && param->name)
1808     param->mode = IMG_CONV_MODE_WALLPAPER;
1809
1810   return param;
1811 }
1812 /*
1813  * vim:ts=2 et
1814  */