#include <assert.h>
#include <gconv.h>
#include <string.h>
#define __need_size_t
#define __need_NULL
#include <stddef.h>
#ifndef STATIC_GCONV
# include <dlfcn.h>
#endif
#ifndef DL_CALL_FCT
# define DL_CALL_FCT(fct, args) fct args
#endif
#if DEFINE_DIRECTION_OBJECTS || DEFINE_INIT
static int from_object;
static int to_object;
# ifndef FROM_DIRECTION
# define FROM_DIRECTION (step->__data == &from_object)
# endif
#else
# ifndef FROM_DIRECTION
# error "FROM_DIRECTION must be provided if direction objects are not used"
# endif
#endif
#ifndef MAX_NEEDED_FROM
# define MAX_NEEDED_FROM MIN_NEEDED_FROM
#endif
#ifndef MAX_NEEDED_TO
# define MAX_NEEDED_TO MIN_NEEDED_TO
#endif
#ifndef FROM_LOOP_MIN_NEEDED_FROM
# define FROM_LOOP_MIN_NEEDED_FROM MIN_NEEDED_FROM
#endif
#ifndef FROM_LOOP_MAX_NEEDED_FROM
# define FROM_LOOP_MAX_NEEDED_FROM MAX_NEEDED_FROM
#endif
#ifndef FROM_LOOP_MIN_NEEDED_TO
# define FROM_LOOP_MIN_NEEDED_TO MIN_NEEDED_TO
#endif
#ifndef FROM_LOOP_MAX_NEEDED_TO
# define FROM_LOOP_MAX_NEEDED_TO MAX_NEEDED_TO
#endif
#ifndef TO_LOOP_MIN_NEEDED_FROM
# define TO_LOOP_MIN_NEEDED_FROM MIN_NEEDED_TO
#endif
#ifndef TO_LOOP_MAX_NEEDED_FROM
# define TO_LOOP_MAX_NEEDED_FROM MAX_NEEDED_TO
#endif
#ifndef TO_LOOP_MIN_NEEDED_TO
# define TO_LOOP_MIN_NEEDED_TO MIN_NEEDED_FROM
#endif
#ifndef TO_LOOP_MAX_NEEDED_TO
# define TO_LOOP_MAX_NEEDED_TO MAX_NEEDED_FROM
#endif
#ifdef _STRING_ARCH_unaligned
# define get16u(addr) *((__const uint16_t *) (addr))
# define get32u(addr) *((__const uint32_t *) (addr))
# define put16u(addr, val) *((uint16_t *) (addr)) = (val)
# define put32u(addr, val) *((uint32_t *) (addr)) = (val)
#else
# if __BYTE_ORDER == __LITTLE_ENDIAN
# define get16u(addr) \
(((__const unsigned char *) (addr))[1] << 8 \
| ((__const unsigned char *) (addr))[0])
# define get32u(addr) \
(((((__const unsigned char *) (addr))[3] << 8 \
| ((__const unsigned char *) (addr))[2]) << 8 \
| ((__const unsigned char *) (addr))[1]) << 8 \
| ((__const unsigned char *) (addr))[0])
# define put16u(addr, val) \
({ uint16_t __val = (val); \
((unsigned char *) (addr))[0] = __val; \
((unsigned char *) (addr))[1] = __val >> 8; \
(void) 0; })
# define put32u(addr, val) \
({ uint32_t __val = (val); \
((unsigned char *) (addr))[0] = __val; \
__val >>= 8; \
((unsigned char *) (addr))[1] = __val; \
__val >>= 8; \
((unsigned char *) (addr))[2] = __val; \
__val >>= 8; \
((unsigned char *) (addr))[3] = __val; \
(void) 0; })
# else
# define get16u(addr) \
(((__const unsigned char *) (addr))[0] << 8 \
| ((__const unsigned char *) (addr))[1])
# define get32u(addr) \
(((((__const unsigned char *) (addr))[0] << 8 \
| ((__const unsigned char *) (addr))[1]) << 8 \
| ((__const unsigned char *) (addr))[2]) << 8 \
| ((__const unsigned char *) (addr))[3])
# define put16u(addr, val) \
({ uint16_t __val = (val); \
((unsigned char *) (addr))[1] = __val; \
((unsigned char *) (addr))[0] = __val >> 8; \
(void) 0; })
# define put32u(addr, val) \
({ uint32_t __val = (val); \
((unsigned char *) (addr))[3] = __val; \
__val >>= 8; \
((unsigned char *) (addr))[2] = __val; \
__val >>= 8; \
((unsigned char *) (addr))[1] = __val; \
__val >>= 8; \
((unsigned char *) (addr))[0] = __val; \
(void) 0; })
# endif
#endif
#if !defined RESET_INPUT_BUFFER && !defined SAVE_RESET_STATE
# if FROM_LOOP_MIN_NEEDED_FROM == FROM_LOOP_MAX_NEEDED_FROM \
&& FROM_LOOP_MIN_NEEDED_TO == FROM_LOOP_MAX_NEEDED_TO \
&& TO_LOOP_MIN_NEEDED_FROM == TO_LOOP_MAX_NEEDED_FROM \
&& TO_LOOP_MIN_NEEDED_TO == TO_LOOP_MAX_NEEDED_TO
# define RESET_INPUT_BUFFER \
if (FROM_DIRECTION) \
{ \
if (FROM_LOOP_MIN_NEEDED_FROM % FROM_LOOP_MIN_NEEDED_TO == 0) \
*inptrp -= (outbuf - outerr) \
* (FROM_LOOP_MIN_NEEDED_FROM / FROM_LOOP_MIN_NEEDED_TO); \
else if (FROM_LOOP_MIN_NEEDED_TO % FROM_LOOP_MIN_NEEDED_FROM == 0) \
*inptrp -= (outbuf - outerr) \
/ (FROM_LOOP_MIN_NEEDED_TO / FROM_LOOP_MIN_NEEDED_FROM \
? : 1); \
else \
*inptrp -= ((outbuf - outerr) / FROM_LOOP_MIN_NEEDED_TO) \
* FROM_LOOP_MIN_NEEDED_FROM; \
} \
else \
{ \
if (TO_LOOP_MIN_NEEDED_FROM % TO_LOOP_MIN_NEEDED_TO == 0) \
*inptrp -= (outbuf - outerr) \
* (TO_LOOP_MIN_NEEDED_FROM / TO_LOOP_MIN_NEEDED_TO); \
else if (TO_LOOP_MIN_NEEDED_TO % TO_LOOP_MIN_NEEDED_FROM == 0) \
*inptrp -= (outbuf - outerr) \
/ (TO_LOOP_MIN_NEEDED_TO / TO_LOOP_MIN_NEEDED_FROM ? : 1); \
else \
*inptrp -= ((outbuf - outerr) / TO_LOOP_MIN_NEEDED_TO) \
* TO_LOOP_MIN_NEEDED_FROM; \
}
# endif
#endif
#if DEFINE_INIT
# ifndef CHARSET_NAME
# error "CHARSET_NAME not defined"
# endif
extern int gconv_init (struct __gconv_step *step);
int
gconv_init (struct __gconv_step *step)
{
if (strcmp (step->__from_name, CHARSET_NAME) == 0)
{
step->__data = &from_object;
step->__min_needed_from = FROM_LOOP_MIN_NEEDED_FROM;
step->__max_needed_from = FROM_LOOP_MAX_NEEDED_FROM;
step->__min_needed_to = FROM_LOOP_MIN_NEEDED_TO;
step->__max_needed_to = FROM_LOOP_MAX_NEEDED_TO;
#ifdef FROM_ONEBYTE
step->__btowc_fct = FROM_ONEBYTE;
#endif
}
else if (__builtin_expect (strcmp (step->__to_name, CHARSET_NAME), 0) == 0)
{
step->__data = &to_object;
step->__min_needed_from = TO_LOOP_MIN_NEEDED_FROM;
step->__max_needed_from = TO_LOOP_MAX_NEEDED_FROM;
step->__min_needed_to = TO_LOOP_MIN_NEEDED_TO;
step->__max_needed_to = TO_LOOP_MAX_NEEDED_TO;
}
else
return __GCONV_NOCONV;
#ifdef SAVE_RESET_STATE
step->__stateful = 1;
#else
step->__stateful = 0;
#endif
return __GCONV_OK;
}
#endif
#if DEFINE_FINI
#endif
#ifndef EXTRA_LOOP_ARGS
# define EXTRA_LOOP_ARGS
#endif
#ifndef FUNCTION_NAME
# define FUNCTION_NAME gconv
#endif
#define SINGLE(fct) SINGLE2 (fct)
#define SINGLE2(fct) fct##_single
extern int FUNCTION_NAME (struct __gconv_step *step,
struct __gconv_step_data *data,
const unsigned char **inptrp,
const unsigned char *inend,
unsigned char **outbufstart, size_t *irreversible,
int do_flush, int consume_incomplete);
int
FUNCTION_NAME (struct __gconv_step *step, struct __gconv_step_data *data,
const unsigned char **inptrp, const unsigned char *inend,
unsigned char **outbufstart, size_t *irreversible, int do_flush,
int consume_incomplete)
{
struct __gconv_step *next_step = step + 1;
struct __gconv_step_data *next_data = data + 1;
__gconv_fct fct;
int status;
fct = (data->__flags & __GCONV_IS_LAST) ? NULL : next_step->__fct;
if (__builtin_expect (do_flush, 0))
{
assert (outbufstart == NULL);
status = __GCONV_OK;
#ifdef EMIT_SHIFT_TO_INIT
if (do_flush == 1)
{
unsigned char *outbuf = data->__outbuf;
unsigned char *outstart = outbuf;
unsigned char *outend = data->__outbufend;
# ifdef PREPARE_LOOP
PREPARE_LOOP
# endif
# ifdef SAVE_RESET_STATE
SAVE_RESET_STATE (1);
# endif
EMIT_SHIFT_TO_INIT;
if (status == __GCONV_OK)
{
if (data->__flags & __GCONV_IS_LAST)
data->__outbuf = outbuf;
else
{
if (outbuf > outstart)
{
const unsigned char *outerr = outstart;
int result;
result = DL_CALL_FCT (fct, (next_step, next_data,
&outerr, outbuf, NULL,
irreversible, 0,
consume_incomplete));
if (result != __GCONV_EMPTY_INPUT)
{
if (__builtin_expect (outerr != outbuf, 0))
{
outbuf = outstart;
# ifdef SAVE_RESET_STATE
SAVE_RESET_STATE (0);
# endif
}
status = result;
}
}
if (status == __GCONV_OK)
status = DL_CALL_FCT (fct, (next_step, next_data, NULL,
NULL, NULL, irreversible, 1,
consume_incomplete));
}
}
}
else
#endif
{
memset (data->__statep, '\0', sizeof (*data->__statep));
if (! (data->__flags & __GCONV_IS_LAST))
status = DL_CALL_FCT (fct, (next_step, next_data, NULL, NULL,
NULL, irreversible, do_flush,
consume_incomplete));
}
}
else
{
const unsigned char *inptr = *inptrp;
unsigned char *outbuf = (__builtin_expect (outbufstart == NULL, 1)
? data->__outbuf : *outbufstart);
unsigned char *outend = data->__outbufend;
unsigned char *outstart;
size_t lirreversible = 0;
size_t *lirreversiblep = irreversible ? &lirreversible : NULL;
#define POSSIBLY_UNALIGNED \
(!defined _STRING_ARCH_unaligned \
&& (((FROM_LOOP_MIN_NEEDED_FROM != 1 \
&& FROM_LOOP_MAX_NEEDED_FROM % FROM_LOOP_MIN_NEEDED_FROM == 0) \
&& (FROM_LOOP_MIN_NEEDED_TO != 1 \
&& FROM_LOOP_MAX_NEEDED_TO % FROM_LOOP_MIN_NEEDED_TO == 0)) \
|| ((TO_LOOP_MIN_NEEDED_FROM != 1 \
&& TO_LOOP_MAX_NEEDED_FROM % TO_LOOP_MIN_NEEDED_FROM == 0) \
&& (TO_LOOP_MIN_NEEDED_TO != 1 \
&& TO_LOOP_MAX_NEEDED_TO % TO_LOOP_MIN_NEEDED_TO == 0))))
#if POSSIBLY_UNALIGNED
int unaligned;
# define GEN_unaligned(name) GEN_unaligned2 (name)
# define GEN_unaligned2(name) name##_unaligned
#else
# define unaligned 0
#endif
#ifdef PREPARE_LOOP
PREPARE_LOOP
#endif
#if FROM_LOOP_MAX_NEEDED_FROM > 1 || TO_LOOP_MAX_NEEDED_FROM > 1
if (((FROM_LOOP_MAX_NEEDED_FROM > 1 && TO_LOOP_MAX_NEEDED_FROM > 1)
|| (FROM_LOOP_MAX_NEEDED_FROM > 1 && FROM_DIRECTION)
|| (TO_LOOP_MAX_NEEDED_FROM > 1 && !FROM_DIRECTION))
&& consume_incomplete && (data->__statep->__count & 7) != 0)
{
assert (outbufstart == NULL);
# if FROM_LOOP_MAX_NEEDED_FROM > 1
if (TO_LOOP_MAX_NEEDED_FROM == 1 || FROM_DIRECTION)
status = SINGLE(FROM_LOOP) (step, data, inptrp, inend, &outbuf,
outend, lirreversiblep
EXTRA_LOOP_ARGS);
# endif
# if !ONE_DIRECTION
# if FROM_LOOP_MAX_NEEDED_FROM > 1 && TO_LOOP_MAX_NEEDED_FROM > 1
else
# endif
# if TO_LOOP_MAX_NEEDED_FROM > 1
status = SINGLE(TO_LOOP) (step, data, inptrp, inend, &outbuf,
outend, lirreversiblep EXTRA_LOOP_ARGS);
# endif
# endif
if (__builtin_expect (status, __GCONV_OK) != __GCONV_OK)
return status;
}
#endif
#if POSSIBLY_UNALIGNED
unaligned =
((FROM_DIRECTION
&& ((uintptr_t) inptr % FROM_LOOP_MIN_NEEDED_FROM != 0
|| ((data->__flags & __GCONV_IS_LAST)
&& (uintptr_t) outbuf % FROM_LOOP_MIN_NEEDED_TO != 0)))
|| (!FROM_DIRECTION
&& (((data->__flags & __GCONV_IS_LAST)
&& (uintptr_t) outbuf % TO_LOOP_MIN_NEEDED_TO != 0)
|| (uintptr_t) inptr % TO_LOOP_MIN_NEEDED_FROM != 0)));
#endif
while (1)
{
struct __gconv_trans_data *trans;
inptr = *inptrp;
outstart = outbuf;
#ifdef SAVE_RESET_STATE
SAVE_RESET_STATE (1);
#endif
if (__builtin_expect (!unaligned, 1))
{
if (FROM_DIRECTION)
status = FROM_LOOP (step, data, inptrp, inend, &outbuf, outend,
lirreversiblep EXTRA_LOOP_ARGS);
else
status = TO_LOOP (step, data, inptrp, inend, &outbuf, outend,
lirreversiblep EXTRA_LOOP_ARGS);
}
#if POSSIBLY_UNALIGNED
else
{
if (FROM_DIRECTION)
status = GEN_unaligned (FROM_LOOP) (step, data, inptrp, inend,
&outbuf, outend,
lirreversiblep
EXTRA_LOOP_ARGS);
else
status = GEN_unaligned (TO_LOOP) (step, data, inptrp, inend,
&outbuf, outend,
lirreversiblep
EXTRA_LOOP_ARGS);
}
#endif
if (__builtin_expect (outbufstart != NULL, 0))
{
*outbufstart = outbuf;
return status;
}
for (trans = data->__trans; trans != NULL; trans = trans->__next)
if (trans->__trans_context_fct != NULL)
DL_CALL_FCT (trans->__trans_context_fct,
(trans->__data, inptr, *inptrp, outstart, outbuf));
++data->__invocation_counter;
if (__builtin_expect (data->__flags & __GCONV_IS_LAST, 0))
{
data->__outbuf = outbuf;
*irreversible += lirreversible;
break;
}
if (__builtin_expect (outbuf > outstart, 1))
{
const unsigned char *outerr = data->__outbuf;
int result;
result = DL_CALL_FCT (fct, (next_step, next_data, &outerr,
outbuf, NULL, irreversible, 0,
consume_incomplete));
if (result != __GCONV_EMPTY_INPUT)
{
if (__builtin_expect (outerr != outbuf, 0))
{
#ifdef RESET_INPUT_BUFFER
RESET_INPUT_BUFFER;
#else
size_t nstatus;
*inptrp = inptr;
outbuf = outstart;
# ifdef SAVE_RESET_STATE
SAVE_RESET_STATE (0);
# endif
if (__builtin_expect (!unaligned, 1))
{
if (FROM_DIRECTION)
nstatus = FROM_LOOP (step, data, inptrp, inend,
&outbuf, outerr,
lirreversiblep
EXTRA_LOOP_ARGS);
else
nstatus = TO_LOOP (step, data, inptrp, inend,
&outbuf, outerr,
lirreversiblep
EXTRA_LOOP_ARGS);
}
# if POSSIBLY_UNALIGNED
else
{
if (FROM_DIRECTION)
nstatus = GEN_unaligned (FROM_LOOP) (step, data,
inptrp, inend,
&outbuf,
outerr,
lirreversiblep
EXTRA_LOOP_ARGS);
else
nstatus = GEN_unaligned (TO_LOOP) (step, data,
inptrp, inend,
&outbuf, outerr,
lirreversiblep
EXTRA_LOOP_ARGS);
}
# endif
assert (outbuf == outerr);
assert (nstatus == __GCONV_FULL_OUTPUT);
if (__builtin_expect (outbuf == outstart, 0))
--data->__invocation_counter;
#endif
}
status = result;
}
else
if (status == __GCONV_FULL_OUTPUT)
{
status = __GCONV_OK;
outbuf = data->__outbuf;
}
}
if (status != __GCONV_OK)
break;
outbuf = data->__outbuf;
}
#ifdef END_LOOP
END_LOOP
#endif
#if FROM_LOOP_MAX_NEEDED_FROM > 1 || TO_LOOP_MAX_NEEDED_FROM > 1
if (((FROM_LOOP_MAX_NEEDED_FROM > 1 && TO_LOOP_MAX_NEEDED_FROM > 1)
|| (FROM_LOOP_MAX_NEEDED_FROM > 1 && FROM_DIRECTION)
|| (TO_LOOP_MAX_NEEDED_FROM > 1 && !FROM_DIRECTION))
&& __builtin_expect (consume_incomplete, 0)
&& status == __GCONV_INCOMPLETE_INPUT)
{
# ifdef STORE_REST
mbstate_t *state = data->__statep;
STORE_REST
# else
size_t cnt;
assert (inend - *inptrp < 4);
for (cnt = 0; *inptrp < inend; ++cnt)
data->__statep->__value.__wchb[cnt] = *(*inptrp)++;
data->__statep->__count &= ~7;
data->__statep->__count |= cnt;
# endif
}
#endif
#undef unaligned
#undef POSSIBLY_UNALIGNED
}
return status;
}
#undef DEFINE_INIT
#undef CHARSET_NAME
#undef DEFINE_FINI
#undef MIN_NEEDED_FROM
#undef MIN_NEEDED_TO
#undef MAX_NEEDED_FROM
#undef MAX_NEEDED_TO
#undef FROM_LOOP_MIN_NEEDED_FROM
#undef FROM_LOOP_MAX_NEEDED_FROM
#undef FROM_LOOP_MIN_NEEDED_TO
#undef FROM_LOOP_MAX_NEEDED_TO
#undef TO_LOOP_MIN_NEEDED_FROM
#undef TO_LOOP_MAX_NEEDED_FROM
#undef TO_LOOP_MIN_NEEDED_TO
#undef TO_LOOP_MAX_NEEDED_TO
#undef DEFINE_DIRECTION_OBJECTS
#undef FROM_DIRECTION
#undef EMIT_SHIFT_TO_INIT
#undef FROM_LOOP
#undef TO_LOOP
#undef ONE_DIRECTION
#undef SAVE_RESET_STATE
#undef RESET_INPUT_BUFFER
#undef FUNCTION_NAME
#undef PREPARE_LOOP
#undef END_LOOP
#undef EXTRA_LOOP_ARGS
#undef STORE_REST
#undef FROM_ONEBYTE