diff options
Diffstat (limited to 'iconv/loop.c')
-rw-r--r-- | iconv/loop.c | 98 |
1 files changed, 95 insertions, 3 deletions
diff --git a/iconv/loop.c b/iconv/loop.c index 5c5948f46e..9af06bccdc 100644 --- a/iconv/loop.c +++ b/iconv/loop.c @@ -45,13 +45,90 @@ UPDATE_PARAMS code to store result in params. */ +#include <endian.h> #include <gconv.h> +#include <stdint.h> +#include <string.h> #include <wchar.h> #include <sys/param.h> /* For MIN. */ #define __need_size_t #include <stddef.h> +/* We have to provide support for machines which are not able to handled + unaligned memory accesses. Some of the character encodings have + representations with a fixed width of 2 or 4 bytes. But if we cannot + access unaligned memory we still have to read byte-wise. */ +#undef FCTNAME2 +#if defined _STRING_ARCH_unaligned || !defined DEFINE_UNALIGNED +/* We can handle unaligned memory access. */ +# define get16(addr) *((uint16_t *) (addr)) +# define get32(addr) *((uint32_t *) (addr)) + +/* We need no special support for writing values either. */ +# define put16(addr, val) *((uint16_t *) (addr)) = (val) +# define put32(addr, val) *((uint32_t *) (addr)) = (val) + +# define FCTNAME2(name) name +#else +/* Distinguish between big endian and little endian. */ +# if __BYTE_ORDER == __LITTLE_ENDIAN +# define get16(addr) \ + (((__const unsigned char *) (addr))[1] << 8 \ + | ((__const unsigned char *) (addr))[0]) +# define get32(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 put16(addr, val) \ + ({ uint16_t __val = (val); \ + ((__const unsigned char *) (addr))[0] = __val; \ + ((__const unsigned char *) (addr))[1] = __val >> 8; \ + (void) 0; }) +# define put32(addr, val) \ + ({ uint16_t __val = (val); \ + ((__const unsigned char *) (addr))[0] = __val; \ + __val >>= 8; \ + ((__const unsigned char *) (addr))[1] = __val; \ + __val >>= 8; \ + ((__const unsigned char *) (addr))[2] = __val; \ + __val >>= 8; \ + ((__const unsigned char *) (addr))[3] = __val; \ + (void) 0; }) +# else +# define get16(addr) \ + (((__const unsigned char *) (addr))[0] << 8 \ + | ((__const unsigned char *) (addr))[1]) +# define get32(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 put16(addr, val) \ + ({ uint16_t __val = (val); \ + ((__const unsigned char *) (addr))[1] = __val; \ + ((__const unsigned char *) (addr))[2] = __val >> 8; \ + (void) 0; }) +# define put32(addr, val) \ + ({ uint16_t __val = (val); \ + ((__const unsigned char *) (addr))[3] = __val; \ + __val >>= 8; \ + ((__const unsigned char *) (addr))[2] = __val; \ + __val >>= 8; \ + ((__const unsigned char *) (addr))[1] = __val; \ + __val >>= 8; \ + ((__const unsigned char *) (addr))[0] = __val; \ + (void) 0; }) +# endif + +# define FCTNAME2(name) name##_unaligned +#endif +#define FCTNAME(name) FCTNAME2(name) + + /* We need at least one byte for the next round. */ #ifndef MIN_NEEDED_INPUT # error "MIN_NEEDED_INPUT definition missing" @@ -92,9 +169,10 @@ /* The function returns the status, as defined in gconv.h. */ static inline int -LOOPFCT (const unsigned char **inptrp, const unsigned char *inend, - unsigned char **outptrp, unsigned char *outend, mbstate_t *state, - void *data, size_t *converted EXTRA_LOOP_DECLS) +FCTNAME (LOOPFCT) (const unsigned char **inptrp, const unsigned char *inend, + unsigned char **outptrp, unsigned char *outend, + mbstate_t *state, void *data, size_t *converted + EXTRA_LOOP_DECLS) { int result = __GCONV_OK; const unsigned char *inptr = *inptrp; @@ -183,6 +261,15 @@ LOOPFCT (const unsigned char **inptrp, const unsigned char *inend, } +/* Include the file a second time to define the function to define the + function to handle unaligned access. */ +#if !defined _STRING_ARCH_unaligned && !defined DEFINE_UNALIGNED +# define DEFINE_UNALIGNED +# include "loop.c" +# undef DEFINE_UNALIGNED +#endif + + /* We remove the macro definitions so that we can include this file again for the definition of another function. */ #undef MIN_NEEDED_INPUT @@ -195,3 +282,8 @@ LOOPFCT (const unsigned char **inptrp, const unsigned char *inend, #undef EXTRA_LOOP_DECLS #undef INIT_PARAMS #undef UPDATE_PARAMS + +#undef get16 +#undef get32 +#undef put16 +#undef put32 |