1
/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
* you may not use this file except in compliance with the License.
6
* You may obtain a copy of the License at
8
* http://www.apache.org/licenses/LICENSE-2.0
10
* Unless required by applicable law or agreed to in writing, software
11
* distributed under the License is distributed on an "AS IS" BASIS,
12
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
* See the License for the specific language governing permissions and
14
* limitations under the License.
18
#include "apu_config.h"
20
#include "apr_strings.h"
21
#include "apr_portable.h"
22
#include "apr_xlate.h"
24
/* If no implementation is available, don't generate code here since
25
* apr_xlate.h emitted macros which return APR_ENOTIMPL.
31
#include <stddef.h> /* for NULL */
36
#if APR_HAVE_STRINGS_H
42
#if APU_HAVE_APR_ICONV
43
#include <apr_iconv.h>
46
#if defined(APU_ICONV_INBUF_CONST) || APU_HAVE_APR_ICONV
47
#define ICONV_INBUF_TYPE const char **
49
#define ICONV_INBUF_TYPE char **
53
#define min(x,y) ((x) <= (y) ? (x) : (y))
63
#elif APU_HAVE_APR_ICONV
69
static const char *handle_special_names(const char *page, apr_pool_t *pool)
71
if (page == APR_DEFAULT_CHARSET) {
72
return apr_os_default_encoding(pool);
74
else if (page == APR_LOCALE_CHARSET) {
75
return apr_os_locale_encoding(pool);
82
static apr_status_t apr_xlate_cleanup(void *convset)
84
apr_xlate_t *old = convset;
86
#if APU_HAVE_APR_ICONV
87
if (old->ich != (apr_iconv_t)-1) {
88
return apr_iconv_close(old->ich, old->pool);
92
if (old->ich != (iconv_t)-1) {
93
if (iconv_close(old->ich)) {
96
/* Sometimes, iconv is not good about setting errno. */
97
return rv ? rv : APR_EINVAL;
106
static void check_sbcs(apr_xlate_t *convset)
108
char inbuf[256], outbuf[256];
109
char *inbufptr = inbuf;
110
char *outbufptr = outbuf;
111
apr_size_t inbytes_left, outbytes_left;
113
apr_size_t translated;
115
for (i = 0; i < sizeof(inbuf); i++) {
119
inbytes_left = outbytes_left = sizeof(inbuf);
120
translated = iconv(convset->ich, (ICONV_INBUF_TYPE)&inbufptr,
121
&inbytes_left, &outbufptr, &outbytes_left);
123
if (translated != (apr_size_t)-1
125
&& outbytes_left == 0) {
126
/* hurray... this is simple translation; save the table,
127
* close the iconv descriptor
130
convset->sbcs_table = apr_palloc(convset->pool, sizeof(outbuf));
131
memcpy(convset->sbcs_table, outbuf, sizeof(outbuf));
132
iconv_close(convset->ich);
133
convset->ich = (iconv_t)-1;
135
/* TODO: add the table to the cache */
138
/* reset the iconv descriptor, since it's now in an undefined
140
iconv_close(convset->ich);
141
convset->ich = iconv_open(convset->topage, convset->frompage);
144
#elif APU_HAVE_APR_ICONV
145
static void check_sbcs(apr_xlate_t *convset)
147
char inbuf[256], outbuf[256];
148
char *inbufptr = inbuf;
149
char *outbufptr = outbuf;
150
apr_size_t inbytes_left, outbytes_left;
152
apr_size_t translated;
155
for (i = 0; i < sizeof(inbuf); i++) {
159
inbytes_left = outbytes_left = sizeof(inbuf);
160
rv = apr_iconv(convset->ich, (ICONV_INBUF_TYPE)&inbufptr,
161
&inbytes_left, &outbufptr, &outbytes_left,
164
if ((rv == APR_SUCCESS)
165
&& (translated != (apr_size_t)-1)
167
&& outbytes_left == 0) {
168
/* hurray... this is simple translation; save the table,
169
* close the iconv descriptor
172
convset->sbcs_table = apr_palloc(convset->pool, sizeof(outbuf));
173
memcpy(convset->sbcs_table, outbuf, sizeof(outbuf));
174
apr_iconv_close(convset->ich, convset->pool);
175
convset->ich = (apr_iconv_t)-1;
177
/* TODO: add the table to the cache */
180
/* reset the iconv descriptor, since it's now in an undefined
182
apr_iconv_close(convset->ich, convset->pool);
183
rv = apr_iconv_open(convset->topage, convset->frompage,
184
convset->pool, &convset->ich);
187
#endif /* APU_HAVE_APR_ICONV */
189
static void make_identity_table(apr_xlate_t *convset)
193
convset->sbcs_table = apr_palloc(convset->pool, 256);
194
for (i = 0; i < 256; i++)
195
convset->sbcs_table[i] = i;
198
APU_DECLARE(apr_status_t) apr_xlate_open(apr_xlate_t **convset,
200
const char *frompage,
209
topage = handle_special_names(topage, pool);
210
frompage = handle_special_names(frompage, pool);
212
new = (apr_xlate_t *)apr_pcalloc(pool, sizeof(apr_xlate_t));
218
new->topage = apr_pstrdup(pool, topage);
219
new->frompage = apr_pstrdup(pool, frompage);
220
if (!new->topage || !new->frompage) {
225
/* search cache of codepage pairs; we may be able to avoid the
226
* expensive iconv_open()
229
set found to non-zero if found in the cache
232
if ((! found) && (strcmp(topage, frompage) == 0)) {
233
/* to and from are the same */
235
make_identity_table(new);
238
#if APU_HAVE_APR_ICONV
240
rv = apr_iconv_open(topage, frompage, pool, &new->ich);
241
if (rv != APR_SUCCESS) {
247
new->ich = (apr_iconv_t)-1;
251
new->ich = iconv_open(topage, frompage);
252
if (new->ich == (iconv_t)-1) {
254
/* Sometimes, iconv is not good about setting errno. */
255
return rv ? rv : APR_EINVAL;
260
new->ich = (iconv_t)-1;
261
#endif /* APU_HAVE_ICONV */
265
apr_pool_cleanup_register(pool, (void *)new, apr_xlate_cleanup,
266
apr_pool_cleanup_null);
270
rv = APR_EINVAL; /* iconv() would return EINVAL if it
271
couldn't handle the pair */
277
APU_DECLARE(apr_status_t) apr_xlate_sb_get(apr_xlate_t *convset, int *onoff)
279
*onoff = convset->sbcs_table != NULL;
283
APU_DECLARE(apr_status_t) apr_xlate_conv_buffer(apr_xlate_t *convset,
285
apr_size_t *inbytes_left,
287
apr_size_t *outbytes_left)
289
apr_status_t status = APR_SUCCESS;
291
#if APU_HAVE_APR_ICONV
292
if (convset->ich != (apr_iconv_t)-1) {
293
const char *inbufptr = inbuf;
294
apr_size_t translated;
295
char *outbufptr = outbuf;
296
status = apr_iconv(convset->ich, &inbufptr, inbytes_left,
297
&outbufptr, outbytes_left, &translated);
299
/* If everything went fine but we ran out of buffer, don't
300
* report it as an error. Caller needs to look at the two
301
* bytes-left values anyway.
303
* There are three expected cases where rc is -1. In each of
304
* these cases, *inbytes_left != 0.
305
* a) the non-error condition where we ran out of output
307
* b) the non-error condition where we ran out of input (i.e.,
308
* the last input character is incomplete)
309
* c) the error condition where the input is invalid
313
case E2BIG: /* out of space on output */
314
status = 0; /* change table lookup code below if you
315
make this an error */
318
case EINVAL: /* input character not complete (yet) */
319
status = APR_INCOMPLETE;
322
case EILSEQ: /* bad input byte */
326
/* Sometimes, iconv is not good about setting errno. */
329
status = APR_INCOMPLETE;
339
if (convset->ich != (iconv_t)-1) {
340
const char *inbufptr = inbuf;
341
char *outbufptr = outbuf;
342
apr_size_t translated;
343
translated = iconv(convset->ich, (ICONV_INBUF_TYPE)&inbufptr,
344
inbytes_left, &outbufptr, outbytes_left);
346
/* If everything went fine but we ran out of buffer, don't
347
* report it as an error. Caller needs to look at the two
348
* bytes-left values anyway.
350
* There are three expected cases where rc is -1. In each of
351
* these cases, *inbytes_left != 0.
352
* a) the non-error condition where we ran out of output
354
* b) the non-error condition where we ran out of input (i.e.,
355
* the last input character is incomplete)
356
* c) the error condition where the input is invalid
358
if (translated == (apr_size_t)-1) {
362
case E2BIG: /* out of space on output */
363
status = 0; /* change table lookup code below if you
364
make this an error */
367
case EINVAL: /* input character not complete (yet) */
368
status = APR_INCOMPLETE;
371
case EILSEQ: /* bad input byte */
375
/* Sometimes, iconv is not good about setting errno. */
377
status = APR_INCOMPLETE;
390
int to_convert = min(*inbytes_left, *outbytes_left);
391
int converted = to_convert;
392
char *table = convset->sbcs_table;
395
*outbuf = table[(unsigned char)*inbuf];
400
*inbytes_left -= converted;
401
*outbytes_left -= converted;
407
APU_DECLARE(apr_int32_t) apr_xlate_conv_byte(apr_xlate_t *convset,
408
unsigned char inchar)
410
if (convset->sbcs_table) {
411
return convset->sbcs_table[inchar];
418
APU_DECLARE(apr_status_t) apr_xlate_close(apr_xlate_t *convset)
420
return apr_pool_cleanup_run(convset->pool, convset, apr_xlate_cleanup);
423
#else /* !APR_HAS_XLATE */
425
APU_DECLARE(apr_status_t) apr_xlate_open(apr_xlate_t **convset,
427
const char *frompage,
433
APU_DECLARE(apr_status_t) apr_xlate_sb_get(apr_xlate_t *convset, int *onoff)
438
APU_DECLARE(apr_int32_t) apr_xlate_conv_byte(apr_xlate_t *convset,
439
unsigned char inchar)
444
APU_DECLARE(apr_status_t) apr_xlate_conv_buffer(apr_xlate_t *convset,
446
apr_size_t *inbytes_left,
448
apr_size_t *outbytes_left)
453
APU_DECLARE(apr_status_t) apr_xlate_close(apr_xlate_t *convset)
458
#endif /* APR_HAS_XLATE */