OSDN Git Service

* merge from 0.8.0 branch.
[modchxj/mod_chxj.git] / src / chxj_encoding.c
1 /*
2  * Copyright (C) 2005-2008 Atsushi Konno All rights reserved.
3  * Copyright (C) 2005 QSDN,Inc. All rights reserved.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 #include "mod_chxj.h"
18 #include "chxj_encoding.h"
19 #include "chxj_apply_convrule.h"
20 #include "chxj_url_encode.h"
21
22 #if 0
23 #if defined(HAVE_LIBICONV_HOOK)
24 #  include "iconv_hook/iconv.h"
25 #else
26 #  if defined(HAVE_LIBICONV)
27 #    include "iconv.h"
28 #  else
29 #    error "Please install libiconv or libiconv_hook. and Please set LD_LIBRARY_PATH."
30 #  endif
31 #endif
32 #endif
33
34 #include <iconv.h>
35
36 static char *
37 do_encoding(
38   request_rec *r,
39   char **ibuf,
40   apr_size_t *ilenp,
41   char **obuf,
42   apr_size_t *olenp,
43   const char *from_code,
44   const char *to_code);
45
46 char *
47 chxj_encoding(request_rec *r, const char *src, apr_size_t *len)
48 {
49   char                *obuf;
50   char                *ibuf;
51   char                *spos;
52   
53   apr_size_t          ilen;
54   apr_size_t          olen;
55   mod_chxj_config     *dconf;
56   chxjconvrule_entry  *entryp;
57   char                *rtn;
58
59   DBG(r,"start chxj_encoding() len=[%d] input[%.*s]", (int)*len, (int)*len, src);
60
61   dconf = ap_get_module_config(r->per_dir_config, &chxj_module);
62   if (dconf == NULL) {
63     DBG(r,"none encoding.");
64     return (char*)src;
65   }
66
67   entryp = chxj_apply_convrule(r, dconf->convrules);
68   if (entryp->encoding == NULL) {
69     DBG(r,"none encoding.");
70     return (char*)src;
71   }
72
73   if ((*(entryp->encoding) == 'n' || *(entryp->encoding) == 'N') 
74       &&   strcasecmp(entryp->encoding, "NONE") == 0) {
75     DBG(r,"none encoding.");
76     return (char*)src;
77   }
78   ilen = *len;
79   ibuf = apr_palloc(r->pool, ilen+1);
80   if (ibuf == NULL) {
81     DBG(r,"end   chxj_encoding()");
82     return (char*)src;
83   }
84   memset(ibuf, 0, ilen+1);
85   memcpy(ibuf, src, ilen);
86
87   olen = ilen * 4 + 1;
88   spos = obuf = apr_palloc(r->pool, olen);
89   if (obuf == NULL) {
90     DBG(r,"memory allocation failure. end   chxj_encoding()");
91     return ibuf;
92   }
93
94   memset(obuf, 0, olen);
95   rtn = NULL;
96   if (IS_EUCJP_STRING(entryp->encoding)) {
97     DBG(r,"try encode convert [%s] -> [%s]", 
98       "EUCJP-WIN",        MOD_CHXJ_INTERNAL_ENCODING);
99     rtn = do_encoding(r, 
100                       &ibuf, 
101                       &ilen, 
102                       &obuf, 
103                       &olen, 
104                       "EUCJP-WIN", 
105                       MOD_CHXJ_INTERNAL_ENCODING);
106     DBG(r, "rtn:[%s]", rtn);
107   }
108   if (rtn == NULL) {
109     DBG(r,"encode convert [%s] -> [%s]", 
110       entryp->encoding,MOD_CHXJ_INTERNAL_ENCODING);
111     rtn = do_encoding(r, 
112                       &ibuf, 
113                       &ilen, 
114                       &obuf, 
115                       &olen, 
116                       entryp->encoding, 
117                       MOD_CHXJ_INTERNAL_ENCODING);
118   }
119   if (rtn == NULL) {
120     ERR(r, "error: convert charactor encoding failure.[%s]", ibuf);
121     return ibuf;
122   }
123   *len = olen;
124   DBG(r,"end   chxj_encoding() len=[%d] obuf=[%.*s]", (int)*len, (int)*len, spos);
125   DBG(r,"end   chxj_encoding() obuf=[%s]", spos);
126   return spos;
127 }
128
129
130 char *
131 chxj_encoding_by_spec(
132   request_rec        *r,
133   device_table       *spec,
134   const char         *src,
135   apr_size_t         *len)
136 {
137   char                *obuf;
138   char                *ibuf;
139   
140   apr_size_t          ilen;
141   apr_size_t          olen;
142   char                *rtn;
143
144   DBG(r,"start chxj_encoding_by_spec() len=[%d] input[%.*s]", (int)*len, (int)*len, src);
145
146   ilen = *len;
147   ibuf = apr_palloc(r->pool, ilen+1);
148   if (ibuf == NULL) {
149     ERR(r, "%s:%d allocation error: not enough memory", __FILE__,__LINE__);
150     return (char*)src;
151   }
152   memset(ibuf, 0, ilen+1);
153   memcpy(ibuf, src, ilen);
154
155   olen = ilen * 4 + 1;
156   obuf = apr_palloc(r->pool, olen);
157   if (obuf == NULL) {
158     ERR(r, "%s:%d allocation error: not enough memory", __FILE__,__LINE__);
159     return ibuf;
160   }
161
162   memset(obuf, 0, (int)olen);
163   rtn = do_encoding(r, &ibuf, &ilen, &obuf, &olen, MOD_CHXJ_INTERNAL_ENCODING, spec->charset);
164   if (rtn == NULL) {
165     ERR(r, "%s:%d error: convert charactor encoding failure.[%s]",__FILE__,__LINE__,ibuf);
166     return ibuf;
167   }
168   *len = strlen(rtn);
169   DBG(r,"end   chxj_encoding() len=[%d] obuf=[%.*s]", (int)*len, (int)*len, rtn);
170   return rtn;
171 }
172
173
174 char *
175 chxj_convert_encoding(
176   request_rec        *r,
177   const char         *from_encoding,
178   const char         *to_encoding,
179   const char         *src,
180   apr_size_t         *len)
181 {
182   char                *obuf;
183   char                *ibuf;
184   
185   apr_size_t          ilen;
186   apr_size_t          olen;
187   char                *rtn;
188
189   DBG(r,"start chxj_convert_encoding() From:[%s] To:[%s] len=[%d] input[%.*s]", from_encoding, to_encoding, (int)*len, (int)*len, src);
190
191   ilen = *len;
192   ibuf = apr_palloc(r->pool, ilen+1);
193   if (ibuf == NULL) {
194     ERR(r, "%s:%d allocation error: not enough memory", __FILE__,__LINE__);
195     return (char*)src;
196   }
197   memset(ibuf, 0, ilen+1);
198   memcpy(ibuf, src, ilen);
199
200   olen = ilen * 4 + 1;
201   obuf = apr_palloc(r->pool, olen);
202   if (obuf == NULL) {
203     ERR(r, "%s:%d allocation error: not enough memory", __FILE__,__LINE__);
204     return ibuf;
205   }
206
207   memset(obuf, 0, (int)olen);
208   rtn = do_encoding(r, &ibuf, &ilen, &obuf, &olen, from_encoding, to_encoding);
209   if (rtn == NULL) {
210     ERR(r, "%s:%d error: convert charactor encoding failure.[%s]",__FILE__,__LINE__,ibuf);
211     return ibuf;
212   }
213   *len = strlen(rtn);
214   DBG(r,"end   chxj_convert_encoding() len=[%d] obuf=[%.*s]", (int)*len, (int)*len, rtn);
215   return rtn;
216 }
217
218
219 static char *
220 do_encoding(
221   request_rec *r,
222   char **ibuf,
223   apr_size_t *ilenp,
224   char **obuf,
225   apr_size_t *olenp,
226   const char *from_code,
227   const char *to_code)
228 {
229   iconv_t cd;
230   size_t  result;
231   apr_size_t ilen;
232   apr_size_t olen;
233   char *spos = *obuf;
234   char *fp, *tp;
235
236   DBG(r,"start do_encoding() from:[%s] --> to:[%s]", from_code, to_code);
237   if (   (IS_SJIS_STRING(from_code)  && IS_SJIS_STRING(to_code))
238       || (IS_EUCJP_STRING(from_code) && IS_EUCJP_STRING(to_code))
239       || (IS_UTF8_STRING(from_code)  && IS_UTF8_STRING(to_code))) {
240     memcpy(*obuf, *ibuf, *ilenp);
241     return *obuf;
242   }
243
244   ilen = *ilenp;
245   olen = *olenp;
246
247   if (IS_EUCJP_STRING(from_code)) {
248     fp = apr_pstrdup(r->pool, "EUCJP-WIN");
249   }
250   else if (IS_SJIS_STRING(from_code)) {
251     fp = apr_pstrdup(r->pool, "CP932");
252   }
253   else if (IS_UTF8_STRING(from_code)) {
254     fp = apr_pstrdup(r->pool, "UTF-8");
255   }
256   else {
257     fp = apr_pstrdup(r->pool, "CP932");
258   }
259
260   if (IS_EUCJP_STRING(to_code)) {
261     tp = apr_pstrdup(r->pool, "EUCJP-WIN");
262   }
263   else if (IS_SJIS_STRING(to_code)) {
264     tp = apr_pstrdup(r->pool, "CP932");
265   }
266   else if (IS_UTF8_STRING(to_code)) {
267     tp = apr_pstrdup(r->pool, "UTF-8");
268   }
269   else {
270     tp = apr_pstrdup(r->pool, "CP932");
271   }
272
273
274   memset(*obuf, 0, olen);
275   cd = (iconv_t)-1;
276   cd = iconv_open(tp, fp);
277   if (cd == (iconv_t)-1) {
278     ERR(r, "try iconv_open failure. cd:[%d] to:[%s] from:[%s]", (int)cd, tp, fp);
279     cd = iconv_open(to_code, from_code);
280     if (cd == (iconv_t)-1) {
281       ERR(r, "iconv_open failure. cd:[%d] to:[%s] from:[%s]", (int)cd, to_code, from_code);
282       return NULL;
283     }
284   }
285   while (ilen > 0) {
286     errno = 0;
287     result = iconv(cd, ibuf, &ilen, obuf, &olen);
288     if (result == (size_t)(-1)) {
289       if (errno == E2BIG) {
290         ERR(r, "outbuf is not an enough size. ");
291         return NULL;
292       }
293       else if (errno == EILSEQ) {
294         ERR(r, "%s:%d invalid multi byte character string to the input. [%.2s]", APLOG_MARK, *ibuf);
295         return NULL;
296       }
297       else if (errno == EINVAL) {
298         ERR(r, "Imperfect character string in the input.");
299         return NULL;
300       }
301       break;
302     }
303   }
304   iconv_close(cd);
305   *olenp = strlen(spos);
306   DBG(r, "end do_encoding() from:[%s] --> to:[%s] spos:[%s]", from_code, to_code, spos);
307   return spos;
308 }
309
310
311 char *
312 chxj_rencoding(
313   request_rec *r, 
314   const char  *src, 
315   apr_size_t  *len)
316 {
317   char                *obuf;
318   char                *ibuf;
319   char                *spos;
320   
321   iconv_t             cd;
322   size_t              result;
323   apr_size_t          ilen;
324   apr_size_t          olen;
325   mod_chxj_config     *dconf;
326   chxjconvrule_entry  *entryp;
327
328   DBG(r,"start chxj_rencoding() input:[%s] len:[%d]", src, *len);
329
330   dconf = ap_get_module_config(r->per_dir_config, &chxj_module);
331   if (! dconf) {
332     DBG(r,"none encoding.");
333     DBG(r,"end   chxj_rencoding()");
334     return (char*)src;
335   }
336
337   entryp = chxj_apply_convrule(r, dconf->convrules);
338   if (! entryp->encoding) {
339     DBG(r,"none encoding.");
340     DBG(r,"end   chxj_rencoding()");
341     return (char*)src;
342   }
343
344   if (STRCASEEQ('n','N', "none", entryp->encoding)) {
345     DBG(r,"none encoding.");
346     DBG(r,"end   chxj_rencoding() no convert.");
347     return (char*)apr_pstrdup(r->pool, src);
348   }
349
350   ilen = *len;
351   ibuf = apr_palloc(r->pool, ilen+1);
352   if (! ibuf) {
353     DBG(r,"end   chxj_rencoding()");
354     ERR(r,"memory allocation error.");
355     return (char *)src;
356   }
357
358   memset(ibuf, 0,   ilen+1);
359   memcpy(ibuf, src, ilen+0);
360
361   olen = ilen * 4 + 1;
362   spos = obuf = apr_palloc(r->pool, olen);
363   if (! obuf) {
364     DBG(r,"end   chxj_rencoding()");
365     ERR(r,"memory allocation error.");
366     return ibuf;
367   }
368   DBG(r,"encode convert [%s] -> [%s]", MOD_CHXJ_INTERNAL_ENCODING, entryp->encoding);
369
370   memset(obuf, 0, olen);
371
372   cd = iconv_open(entryp->encoding, MOD_CHXJ_INTERNAL_ENCODING);
373   if (cd == (iconv_t)-1) {
374     DBG(r,"end   chxj_rencoding()");
375     return ibuf;
376   }
377
378   while (ilen > 0) {
379     result = iconv(cd, &ibuf, &ilen, &obuf, &olen);
380     if (result == (size_t)(-1)) {
381       if (errno == E2BIG) {
382         ERR(r, "outbuf is not an enough size. ");
383         return NULL;
384       }
385       else if (errno == EILSEQ) {
386         ERR(r, "%s:%d invalid multi byte character string to the input. [%s]", APLOG_MARK, ibuf);
387         return NULL;
388       }
389       else if (errno == EINVAL) {
390         ERR(r, "Imperfect character string in the input.");
391         return NULL;
392       }
393       break;
394     }
395   }
396   *len = olen;
397   iconv_close(cd);
398
399   DBG(r,"end   chxj_rencoding() len=[%d] obuf=[%.*s]", (int)*len, (int)*len, spos);
400
401   return spos;
402 }
403
404
405 char *
406 chxj_encoding_parameter(request_rec *r, const char *value)
407 {
408   char *src;
409   char *src_sv;
410   char *pstat;
411   char *spos;
412   char *pair;
413   char *key;
414   char *val;
415   char *vstat;
416   char *param;
417
418   int   use_amp_flag;
419   
420   DBG(r, "start chxj_encoding_parameter()");
421
422   src = apr_pstrdup(r->pool, value);
423
424   spos = strchr(src, '?');
425   if (!spos) {
426     DBG(r, "end   chxj_encoding_parameter()");
427     return src;
428   }
429   *spos++ = 0;
430
431   src_sv = apr_pstrdup(r->pool, src);
432   param  = apr_palloc(r->pool, 1);
433   param[0] = 0;
434
435   for (;;) {
436     apr_size_t len;
437
438     use_amp_flag = 0;
439
440     pair = apr_strtok(spos, "&", &pstat);
441     spos = NULL;
442     if (!pair) break;
443     if (strncasecmp(pair, "amp;", 4) == 0) {
444       pair += 4;
445       use_amp_flag = 1;
446     }
447     key = apr_strtok(pair, "=", &vstat);
448     val = apr_strtok(NULL, "=", &vstat);
449     if (val) {
450       val = chxj_url_decode(r, val);
451       len = (apr_size_t)strlen(val);
452       val = chxj_encoding(r, val, &len);
453       val = chxj_url_encode(r, val);
454       if (strlen(param) == 0) {
455         param = apr_pstrcat(r->pool, param, key, "=", val, NULL);
456       }
457       else {
458         if (use_amp_flag) {
459           param = apr_pstrcat(r->pool, param, "&amp;", key, "=", val, NULL);
460         }
461         else {
462           param = apr_pstrcat(r->pool, param, "&", key, "=", val, NULL);
463         }
464       }
465     }
466     else {
467       if (strlen(param) == 0) {
468         param = apr_pstrcat(r->pool, param, key,  NULL);
469       }
470       else {
471         if (use_amp_flag) {
472           param = apr_pstrcat(r->pool, param, "&amp;", key, NULL);
473         }
474         else {
475           param = apr_pstrcat(r->pool, param, "&", key, NULL);
476         }
477       }
478     }
479   }
480   DBG(r, "end   chxj_encoding_parameter()");
481
482   return apr_pstrcat(r->pool, src_sv, "?", param, NULL);
483 }
484 /*
485  * vim:ts=2 et
486  */