1 /* Copyright 2000-2004 The Apache Software Foundation
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
17 #include "apu_config.h"
19 #include "apr_strings.h"
20 #include "apr_portable.h"
21 #include "apr_xlate.h"
23 /* If no implementation is available, don't generate code here since
24 * apr_xlate.h emitted macros which return APR_ENOTIMPL.
30 #include <stddef.h> /* for NULL */
35 #if APR_HAVE_STRINGS_H
41 #if APU_HAVE_APR_ICONV
42 #include <apr_iconv.h>
45 #if defined(APU_ICONV_INBUF_CONST) || APU_HAVE_APR_ICONV
46 #define ICONV_INBUF_TYPE const char **
48 #define ICONV_INBUF_TYPE char **
52 #define min(x,y) ((x) <= (y) ? (x) : (y))
62 #elif APU_HAVE_APR_ICONV
68 static const char *handle_special_names(const char *page
, apr_pool_t
*pool
)
70 if (page
== APR_DEFAULT_CHARSET
) {
71 return apr_os_default_encoding(pool
);
73 else if (page
== APR_LOCALE_CHARSET
) {
74 return apr_os_locale_encoding(pool
);
81 static apr_status_t
apr_xlate_cleanup(void *convset
)
83 apr_xlate_t
*old
= convset
;
85 #if APU_HAVE_APR_ICONV
86 if (old
->ich
!= (apr_iconv_t
)-1) {
87 return apr_iconv_close(old
->ich
, old
->pool
);
91 if (old
->ich
!= (iconv_t
)-1) {
92 if (iconv_close(old
->ich
)) {
95 /* Sometimes, iconv is not good about setting errno. */
96 return rv
? rv
: APR_EINVAL
;
105 static void check_sbcs(apr_xlate_t
*convset
)
107 char inbuf
[256], outbuf
[256];
108 char *inbufptr
= inbuf
;
109 char *outbufptr
= outbuf
;
110 apr_size_t inbytes_left
, outbytes_left
;
112 apr_size_t translated
;
114 for (i
= 0; i
< sizeof(inbuf
); i
++) {
118 inbytes_left
= outbytes_left
= sizeof(inbuf
);
119 translated
= iconv(convset
->ich
, (ICONV_INBUF_TYPE
)&inbufptr
,
120 &inbytes_left
, &outbufptr
, &outbytes_left
);
122 if (translated
!= (apr_size_t
)-1
124 && outbytes_left
== 0) {
125 /* hurray... this is simple translation; save the table,
126 * close the iconv descriptor
129 convset
->sbcs_table
= apr_palloc(convset
->pool
, sizeof(outbuf
));
130 memcpy(convset
->sbcs_table
, outbuf
, sizeof(outbuf
));
131 iconv_close(convset
->ich
);
132 convset
->ich
= (iconv_t
)-1;
134 /* TODO: add the table to the cache */
137 /* reset the iconv descriptor, since it's now in an undefined
139 iconv_close(convset
->ich
);
140 convset
->ich
= iconv_open(convset
->topage
, convset
->frompage
);
143 #elif APU_HAVE_APR_ICONV
144 static void check_sbcs(apr_xlate_t
*convset
)
146 char inbuf
[256], outbuf
[256];
147 char *inbufptr
= inbuf
;
148 char *outbufptr
= outbuf
;
149 apr_size_t inbytes_left
, outbytes_left
;
151 apr_size_t translated
;
154 for (i
= 0; i
< sizeof(inbuf
); i
++) {
158 inbytes_left
= outbytes_left
= sizeof(inbuf
);
159 rv
= apr_iconv(convset
->ich
, (ICONV_INBUF_TYPE
)&inbufptr
,
160 &inbytes_left
, &outbufptr
, &outbytes_left
,
163 if ((rv
== APR_SUCCESS
)
164 && (translated
!= (apr_size_t
)-1)
166 && outbytes_left
== 0) {
167 /* hurray... this is simple translation; save the table,
168 * close the iconv descriptor
171 convset
->sbcs_table
= apr_palloc(convset
->pool
, sizeof(outbuf
));
172 memcpy(convset
->sbcs_table
, outbuf
, sizeof(outbuf
));
173 apr_iconv_close(convset
->ich
, convset
->pool
);
174 convset
->ich
= (apr_iconv_t
)-1;
176 /* TODO: add the table to the cache */
179 /* reset the iconv descriptor, since it's now in an undefined
181 apr_iconv_close(convset
->ich
, convset
->pool
);
182 rv
= apr_iconv_open(convset
->topage
, convset
->frompage
,
183 convset
->pool
, &convset
->ich
);
186 #endif /* APU_HAVE_APR_ICONV */
188 static void make_identity_table(apr_xlate_t
*convset
)
192 convset
->sbcs_table
= apr_palloc(convset
->pool
, 256);
193 for (i
= 0; i
< 256; i
++)
194 convset
->sbcs_table
[i
] = i
;
197 APU_DECLARE(apr_status_t
) apr_xlate_open(apr_xlate_t
**convset
,
199 const char *frompage
,
208 topage
= handle_special_names(topage
, pool
);
209 frompage
= handle_special_names(frompage
, pool
);
211 new = (apr_xlate_t
*)apr_pcalloc(pool
, sizeof(apr_xlate_t
));
217 new->topage
= apr_pstrdup(pool
, topage
);
218 new->frompage
= apr_pstrdup(pool
, frompage
);
219 if (!new->topage
|| !new->frompage
) {
224 /* search cache of codepage pairs; we may be able to avoid the
225 * expensive iconv_open()
228 set found to non
-zero
if found in the cache
231 if ((! found
) && (strcmp(topage
, frompage
) == 0)) {
232 /* to and from are the same */
234 make_identity_table(new);
237 #if APU_HAVE_APR_ICONV
239 rv
= apr_iconv_open(topage
, frompage
, pool
, &new->ich
);
240 if (rv
!= APR_SUCCESS
) {
246 new->ich
= (apr_iconv_t
)-1;
250 new->ich
= iconv_open(topage
, frompage
);
251 if (new->ich
== (iconv_t
)-1) {
253 /* Sometimes, iconv is not good about setting errno. */
254 return rv
? rv
: APR_EINVAL
;
259 new->ich
= (iconv_t
)-1;
260 #endif /* APU_HAVE_ICONV */
264 apr_pool_cleanup_register(pool
, (void *)new, apr_xlate_cleanup
,
265 apr_pool_cleanup_null
);
269 rv
= APR_EINVAL
; /* iconv() would return EINVAL if it
270 couldn't handle the pair */
276 APU_DECLARE(apr_status_t
) apr_xlate_sb_get(apr_xlate_t
*convset
, int *onoff
)
278 *onoff
= convset
->sbcs_table
!= NULL
;
282 APU_DECLARE(apr_status_t
) apr_xlate_conv_buffer(apr_xlate_t
*convset
,
284 apr_size_t
*inbytes_left
,
286 apr_size_t
*outbytes_left
)
288 apr_status_t status
= APR_SUCCESS
;
290 #if APU_HAVE_APR_ICONV
291 if (convset
->ich
!= (apr_iconv_t
)-1) {
292 const char *inbufptr
= inbuf
;
293 apr_size_t translated
;
294 char *outbufptr
= outbuf
;
295 status
= apr_iconv(convset
->ich
, &inbufptr
, inbytes_left
,
296 &outbufptr
, outbytes_left
, &translated
);
298 /* If everything went fine but we ran out of buffer, don't
299 * report it as an error. Caller needs to look at the two
300 * bytes-left values anyway.
302 * There are three expected cases where rc is -1. In each of
303 * these cases, *inbytes_left != 0.
304 * a) the non-error condition where we ran out of output
306 * b) the non-error condition where we ran out of input (i.e.,
307 * the last input character is incomplete)
308 * c) the error condition where the input is invalid
312 case E2BIG
: /* out of space on output */
313 status
= 0; /* change table lookup code below if you
314 make this an error */
317 case EINVAL
: /* input character not complete (yet) */
318 status
= APR_INCOMPLETE
;
321 case EILSEQ
: /* bad input byte */
325 /* Sometimes, iconv is not good about setting errno. */
328 status
= APR_INCOMPLETE
;
338 if (convset
->ich
!= (iconv_t
)-1) {
339 const char *inbufptr
= inbuf
;
340 char *outbufptr
= outbuf
;
341 apr_size_t translated
;
342 translated
= iconv(convset
->ich
, (ICONV_INBUF_TYPE
)&inbufptr
,
343 inbytes_left
, &outbufptr
, outbytes_left
);
345 /* If everything went fine but we ran out of buffer, don't
346 * report it as an error. Caller needs to look at the two
347 * bytes-left values anyway.
349 * There are three expected cases where rc is -1. In each of
350 * these cases, *inbytes_left != 0.
351 * a) the non-error condition where we ran out of output
353 * b) the non-error condition where we ran out of input (i.e.,
354 * the last input character is incomplete)
355 * c) the error condition where the input is invalid
357 if (translated
== (apr_size_t
)-1) {
361 case E2BIG
: /* out of space on output */
362 status
= 0; /* change table lookup code below if you
363 make this an error */
366 case EINVAL
: /* input character not complete (yet) */
367 status
= APR_INCOMPLETE
;
370 case EILSEQ
: /* bad input byte */
374 /* Sometimes, iconv is not good about setting errno. */
376 status
= APR_INCOMPLETE
;
389 int to_convert
= min(*inbytes_left
, *outbytes_left
);
390 int converted
= to_convert
;
391 char *table
= convset
->sbcs_table
;
394 *outbuf
= table
[(unsigned char)*inbuf
];
399 *inbytes_left
-= converted
;
400 *outbytes_left
-= converted
;
406 APU_DECLARE(apr_int32_t
) apr_xlate_conv_byte(apr_xlate_t
*convset
,
407 unsigned char inchar
)
409 if (convset
->sbcs_table
) {
410 return convset
->sbcs_table
[inchar
];
417 APU_DECLARE(apr_status_t
) apr_xlate_close(apr_xlate_t
*convset
)
419 return apr_pool_cleanup_run(convset
->pool
, convset
, apr_xlate_cleanup
);
422 #else /* !APR_HAS_XLATE */
424 APU_DECLARE(apr_status_t
) apr_xlate_open(apr_xlate_t
**convset
,
426 const char *frompage
,
432 APU_DECLARE(apr_status_t
) apr_xlate_sb_get(apr_xlate_t
*convset
, int *onoff
)
437 APU_DECLARE(apr_int32_t
) apr_xlate_conv_byte(apr_xlate_t
*convset
,
438 unsigned char inchar
)
443 APU_DECLARE(apr_status_t
) apr_xlate_conv_buffer(apr_xlate_t
*convset
,
445 apr_size_t
*inbytes_left
,
447 apr_size_t
*outbytes_left
)
452 APU_DECLARE(apr_status_t
) apr_xlate_close(apr_xlate_t
*convset
)
457 #endif /* APR_HAS_XLATE */