OSDN Git Service

a0daacbfe2b37d2ce38a61b1dc8656382c2521cf
[modchxj/mod_chxj.git] / src / chxj_encoding.c
1 /*
2  * Copyright (C) 2005-2009 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 #include <errno.h>
22 #include <iconv.h>
23
24
25 char *
26 chxj_encoding(request_rec *r, const char *src, apr_size_t *len)
27 {
28   char                *obuf;
29   char                *ibuf;
30   char                *spos;
31   
32   iconv_t             cd;
33   size_t              result;
34   apr_size_t          ilen;
35   apr_size_t          olen;
36   mod_chxj_config     *dconf;
37   chxjconvrule_entry  *entryp;
38   apr_pool_t          *pool;
39
40
41   DBG(r,"start chxj_encoding()");
42
43   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
44
45   if (dconf == NULL) {
46     DBG(r,"none encoding.");
47     return (char*)src;
48   }
49   if ((int)*len < 0) {
50     ERR(r, "runtime exception: chxj_encoding(): invalid string size.[%d]", (int)*len);
51     return (char *)apr_pstrdup(r->pool, "");
52   }
53
54   entryp = chxj_apply_convrule(r, dconf->convrules);
55   if (entryp->encoding == NULL) {
56     DBG(r,"none encoding.");
57     return (char *)src;
58   }
59
60   if (STRCASEEQ('n','N',"none", entryp->encoding)) {
61     DBG(r,"none encoding.");
62     return (char*)src;
63   }
64
65   apr_pool_create(&pool, r->pool);
66   ilen = *len;
67   ibuf = apr_palloc(pool, ilen+1);
68   if (ibuf == NULL) {
69     ERR(r, "runtime exception: chxj_encoding(): Out of memory.");
70     return (char *)src;
71   }
72   memset(ibuf, 0, ilen+1);
73   memcpy(ibuf, src, ilen);
74
75   olen = ilen * 4 + 1;
76   spos = obuf = apr_palloc(pool, olen);
77   if (obuf == NULL) {
78     DBG(r,"end   chxj_encoding()");
79     return ibuf;
80   }
81   DBG(r,"encode convert [%s] -> [%s]", entryp->encoding, "CP932");
82
83   memset(obuf, 0, olen);
84   cd = iconv_open("CP932", entryp->encoding);
85   if (cd == (iconv_t)-1) {
86     if (EINVAL == errno) {
87       ERR(r, "The conversion from %s to %s is not supported by the implementation.", entryp->encoding, "CP932");
88     }
89     else {
90       ERR(r, "iconv open failed. from:[%s] to:[%s] errno:[%d]", entryp->encoding, "CP932", errno);
91     }
92     DBG(r,"end   chxj_encoding()");
93     return ibuf;
94   }
95   while (ilen > 0) {
96     result = iconv(cd, &ibuf, &ilen, &obuf, &olen);
97     if (result == (size_t)(-1)) {
98       if (E2BIG == errno) {
99         ERR(r, "There is not sufficient room at *outbuf.");
100         break;
101       }
102       else if (EILSEQ == errno) {
103         ERR(r, "%s:%d An invalid multibyte sequence has been encountered in the input. input:[%s]", __FILE__,__LINE__,ibuf);
104         chxj_convert_illegal_charactor_sequence(r, entryp, &ibuf, &ilen, &obuf, &olen);
105       }
106       else if (EINVAL == errno) {
107         ERR(r, "An incomplete multibyte sequence has been encountered in the input. input:[%s]", ibuf);
108         break;
109       }
110     }
111   }
112   *len = strlen(spos);
113   iconv_close(cd);
114
115   DBG(r,"end   chxj_encoding() len=[%d] obuf=[%.*s]", (int)*len, (int)*len, spos);
116   return spos;
117 }
118
119
120 void
121 chxj_convert_illegal_charactor_sequence(request_rec *r, chxjconvrule_entry  *entryp, char **ibuf, apr_size_t *ilen, char **obuf, apr_size_t *olen)
122 {
123   if (STRCASEEQ('u','U',"UTF-8", entryp->encoding) || STRCASEEQ('u','U',"UTF8", entryp->encoding)) {
124     if ((0xe0 & **ibuf) == 0xc0) {
125       /* 2byte charactor */
126       **obuf = '?';
127       *obuf += 1;
128       *olen -= 1;
129       *ibuf += 2;
130       DBG(r, "passed 2byte.");
131     }
132     else if ((0xf0 & **ibuf) == 0xe0) {
133       /* 3byte charactor */
134       **obuf = '?';
135       *obuf += 1;
136       *olen -= 1;
137       *ibuf +=3;
138       DBG(r, "passed 3byte.");
139     }
140     else if ((0xf8 & **ibuf) == 0xf0) {
141       /* 4byte charactor */
142       **obuf = '?';
143       *obuf += 1;
144       *olen -= 1;
145       *ibuf +=4;
146       DBG(r, "passed 4byte.");
147     }
148     else if ((0xc0 & **ibuf) == 0x80) {
149       /* 1byte charactor */
150       **obuf = '?';
151       *obuf += 1;
152       *olen -= 1;
153       *ibuf += 1;
154       DBG(r, "passed 1byte.");
155     }
156     else {
157       /* unknown charactor */
158       **obuf = '?';
159       *obuf += 1;
160       *olen -= 1;
161       *ibuf += 1;
162       DBG(r, "passed 1byte.");
163     }
164   }
165   else if (STRCASEEQ('e','E', "EUCJP",               entryp->encoding)
166       ||   STRCASEEQ('c','C', "CSEUCPKDFMTJAPANESE", entryp->encoding)
167       ||   STRCASEEQ('e','E', "EUC-JISX0213",        entryp->encoding)
168       ||   STRCASEEQ('e','E', "EUC-JP-MS",           entryp->encoding)
169       ||   STRCASEEQ('e','E', "EUC-JP",              entryp->encoding)
170       ||   STRCASEEQ('e','E', "EUCJP-MS",            entryp->encoding)
171       ||   STRCASEEQ('e','E', "EUCJP-OPEN",          entryp->encoding)
172       ||   STRCASEEQ('e','E', "EUCJP-WIN",           entryp->encoding)
173       ||   STRCASEEQ('e','E', "EUCJP",               entryp->encoding)) {
174     if ((unsigned char)**ibuf == 0x8F) {
175       /* 3byte charactor */
176       **obuf = '?';
177       *obuf += 1;
178       *olen -= 1;
179       *ibuf +=3;
180       DBG(r, "passed 3byte.");
181     }
182     else {
183       /* 2byte charactor */
184       **obuf = '?';
185       *obuf += 1;
186       *olen -= 1;
187       *ibuf += 2;
188       DBG(r, "passed 2byte.");
189     }
190   }
191   else if (STRCASEEQ('c', 'C', "CP932",     entryp->encoding)
192       ||   STRCASEEQ('c', 'C', "CSIBM932",  entryp->encoding)
193       ||   STRCASEEQ('i', 'I', "IBM-932",   entryp->encoding)
194       ||   STRCASEEQ('i', 'I', "IBM932",    entryp->encoding)
195       ||   STRCASEEQ('m', 'M', "MS932",     entryp->encoding)
196       ||   STRCASEEQ('m', 'M', "MS_KANJI",  entryp->encoding)
197       ||   STRCASEEQ('s', 'S', "SJIS-OPEN", entryp->encoding)
198       ||   STRCASEEQ('s', 'S', "SJIS-WIN",  entryp->encoding)
199       ||   STRCASEEQ('s', 'S', "SJIS",      entryp->encoding)) {
200     if ( ( ((0x81 <= (unsigned char)**ibuf) && (0x9f >= (unsigned char)**ibuf))
201         || ((0xe0 <= (unsigned char)**ibuf) && (0xfc >= (unsigned char)**ibuf)))
202        &&
203        (  ((0x40 <= (unsigned char)*((*ibuf)+1)) && (0x7e >= (unsigned char)*((*ibuf)+1)))
204         ||((0x80 <= (unsigned char)*((*ibuf)+1)) && (0xfc >= (unsigned char)*((*ibuf)+1))))) {
205       /* 2byte charactor */
206       **obuf = '?';
207       *obuf += 1;
208       *olen -= 1;
209       *ibuf += 2;
210       DBG(r, "passed 2byte.");
211     }
212     else {
213       /* 1byte charactor */
214       **obuf = '?';
215       *obuf += 1;
216       *olen -= 1;
217       *ibuf += 1;
218       DBG(r, "passed 1byte.");
219     }
220   }
221   else {
222     /* unknown 1byte charactor */
223     **obuf = '?';
224     *obuf += 1;
225     *olen -= 1;
226     *ibuf += 1;
227     DBG(r, "passed 1byte.");
228   }
229   if (ibuf && *ibuf) {
230     *ilen = strlen(*ibuf);
231     DBG(r, "new len = [%" APR_SIZE_T_FMT "].", (apr_size_t)*ilen);
232   }
233 }
234
235
236 char *
237 chxj_rencoding(request_rec *r, const char *src, apr_size_t *len)
238 {
239   char                *obuf;
240   char                *ibuf;
241   char                *spos;
242   
243   iconv_t             cd;
244   size_t              result;
245   apr_size_t          ilen;
246   apr_size_t          olen;
247   mod_chxj_config     *dconf;
248   chxjconvrule_entry  *entryp;
249
250   DBG(r,"start chxj_rencoding()");
251
252   if ((int)*len < 0) {
253     ERR(r, "runtime exception: chxj_rencoding(): invalid string size.[%d]", (int)*len);
254     return (char *)apr_pstrdup(r->pool, "");
255   }
256
257   dconf = chxj_get_module_config(r->per_dir_config, &chxj_module);
258   if (! dconf) {
259     DBG(r,"none encoding.");
260     DBG(r,"end   chxj_rencoding()");
261     return (char*)src;
262   }
263
264   entryp = chxj_apply_convrule(r, dconf->convrules);
265   if (! entryp->encoding) {
266     DBG(r,"none encoding.");
267     DBG(r,"end   chxj_rencoding()");
268     return (char*)src;
269   }
270
271   if (STRCASEEQ('n','N',"none", entryp->encoding)) {
272     DBG(r,"none encoding.");
273     DBG(r,"end   chxj_rencoding()");
274     return (char*)src;
275   }
276
277   ilen = *len;
278   ibuf = apr_palloc(r->pool, ilen+1);
279   if (! ibuf) {
280     DBG(r,"end   chxj_rencoding()");
281     return (char*)src;
282   }
283
284   memset(ibuf, 0,   ilen+1);
285   memcpy(ibuf, src, ilen+0);
286
287   olen = ilen * 4 + 1;
288   spos = obuf = apr_palloc(r->pool, olen);
289   if (! obuf) {
290     DBG(r,"end   chxj_rencoding()");
291     return ibuf;
292   }
293   DBG(r,"encode convert [%s] -> [%s]", "CP932", entryp->encoding);
294
295   memset(obuf, 0, olen);
296
297   cd = iconv_open(entryp->encoding, "CP932");
298   if (cd == (iconv_t)-1) {
299     if (EINVAL == errno) {
300       ERR(r, "The conversion from %s to %s is not supported by the implementation.", "CP932", entryp->encoding);
301     }
302     DBG(r,"end   chxj_rencoding()");
303     return ibuf;
304   }
305
306   while (ilen > 0) {
307     result = iconv(cd, &ibuf, &ilen, &obuf, &olen);
308     if (result == (size_t)(-1)) {
309       if (E2BIG == errno) {
310         ERR(r, "There is not sufficient room at *outbuf");
311         break;
312       }
313       else if (EILSEQ == errno) {
314         ERR(r, "An invalid multibyte sequence has been encountered in the input. input:[%s]", ibuf);
315         chxj_convert_illegal_charactor_sequence(r, entryp, &ibuf, &ilen, &obuf, &olen);
316       }
317       else if (EINVAL == errno) {
318         ERR(r, "An incomplete multibyte sequence has been encountered in the input. input:[%s]", ibuf);
319         break;
320       }
321     }
322   }
323
324   *len = strlen(spos);
325   iconv_close(cd);
326
327   DBG(r,"end   chxj_rencoding() len=[%d] obuf=[%.*s]", (int)*len, (int)*len, spos);
328
329   return spos;
330 }
331
332
333 char *
334 chxj_encoding_parameter(request_rec *r, const char *value)
335 {
336   char *src;
337   char *src_sv;
338   char *pstat;
339   char *spos;
340   char *pair;
341   char *key;
342   char *val;
343   char *vstat;
344   char *param;
345   char *anchor_pos;
346   char *anchor = NULL;
347
348   int   use_amp_flag;
349   
350   DBG(r, "start chxj_encoding_parameter()");
351
352   src = apr_pstrdup(r->pool, value);
353
354   anchor_pos = strchr(src, '#');
355   if (anchor_pos) {
356     anchor_pos++;
357     anchor = apr_pstrdup(r->pool, anchor_pos);
358     anchor_pos--;
359     *anchor_pos = 0;
360   }
361
362   spos = strchr(src, '?');
363   if (!spos) {
364     DBG(r, "end   chxj_encoding_parameter()");
365     if (anchor_pos) {
366       return apr_pstrcat(r->pool, src, "#", anchor, NULL);
367     } else {
368       return src;
369     }
370   }
371   *spos++ = 0;
372
373   src_sv = apr_pstrdup(r->pool, src);
374   param  = apr_palloc(r->pool, 1);
375   param[0] = 0;
376
377   for (;;) {
378     apr_size_t len;
379     char *sep_pos;
380
381     use_amp_flag = 0;
382
383     pair = apr_strtok(spos, "&", &pstat);
384     spos = NULL;
385     if (!pair) break;
386     if (strncasecmp(pair, "amp;", 4) == 0) {
387       pair += 4;
388       use_amp_flag = 1;
389     }
390     sep_pos = strchr(pair, '=');
391     if (pair == sep_pos) {
392       key = apr_pstrdup(r->pool, "");
393     }
394     else {
395       key = apr_strtok(pair, "=", &vstat);
396       pair = NULL;
397     }
398     if (key) {
399       apr_size_t klen = (apr_size_t)strlen(key);
400       key = chxj_url_decode(r->pool, key);
401       len = (apr_size_t)strlen(key);
402       if (klen != len) {
403         key = chxj_encoding(r, key, &len);
404       }
405       key = chxj_url_encode(r->pool, key);
406     }
407     val = apr_strtok(pair, "=", &vstat);
408     if (! val && sep_pos) {
409       val = apr_pstrdup(r->pool, "");
410     }
411     if (val) {
412       apr_size_t vlen = (apr_size_t)strlen(val);
413       val = chxj_url_decode(r->pool, val);
414       len = (apr_size_t)strlen(val);
415       if (vlen != len) {
416         val = chxj_encoding(r, val, &len);
417       }
418       val = chxj_url_encode(r->pool, val);
419       if (strlen(param) == 0) {
420         param = apr_pstrcat(r->pool, param, key, "=", val, NULL);
421       }
422       else {
423         if (use_amp_flag) {
424           param = apr_pstrcat(r->pool, param, "&amp;", key, "=", val, NULL);
425         }
426         else {
427           param = apr_pstrcat(r->pool, param, "&", key, "=", val, NULL);
428         }
429       }
430     }
431     else {
432       if (strlen(param) == 0) {
433         param = apr_pstrcat(r->pool, param, key,  NULL);
434       }
435       else {
436         if (use_amp_flag) {
437           param = apr_pstrcat(r->pool, param, "&amp;", key, NULL);
438         }
439         else {
440           param = apr_pstrcat(r->pool, param, "&", key, NULL);
441         }
442       }
443     }
444   }
445   DBG(r, "end   chxj_encoding_parameter()");
446
447   if (anchor_pos) {
448     return apr_pstrcat(r->pool, src_sv, "?", param, "#", anchor, NULL);
449   } else {
450     return apr_pstrcat(r->pool, src_sv, "?", param, NULL);
451   }
452 }
453 /*
454  * vim:ts=2 et
455  */