📄 gconv_simple.c
字号:
/* Simple transformations functions. Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */#include <byteswap.h>#include <dlfcn.h>#include <endian.h>#include <errno.h>#include <gconv.h>#include <stdint.h>#include <stdlib.h>#include <string.h>#include <wchar.h>#include <sys/param.h>#define BUILTIN_ALIAS(s1, s2) /* nothing */#define BUILTIN_TRANSFORMATION(From, To, Cost, Name, Fct, MinF, MaxF, \ MinT, MaxT) \ extern int Fct (struct __gconv_step *, struct __gconv_step_data *, \ __const unsigned char **, __const unsigned char *, \ unsigned char **, size_t *, int, int);#include "gconv_builtin.h"#ifndef EILSEQ# define EILSEQ EINVAL#endif/* Transform from the internal, UCS4-like format, to UCS4. The difference between the internal ucs4 format and the real UCS4 format is, if any, the endianess. The Unicode/ISO 10646 says that unless some higher protocol specifies it differently, the byte order is big endian.*/#define DEFINE_INIT 0#define DEFINE_FINI 0#define MIN_NEEDED_FROM 4#define MIN_NEEDED_TO 4#define FROM_DIRECTION 1#define FROM_LOOP internal_ucs4_loop#define TO_LOOP internal_ucs4_loop /* This is not used. */#define FUNCTION_NAME __gconv_transform_internal_ucs4static inline intinternal_ucs4_loop (struct __gconv_step *step, struct __gconv_step_data *step_data, const unsigned char **inptrp, const unsigned char *inend, unsigned char **outptrp, unsigned char *outend, size_t *irreversible){ const unsigned char *inptr = *inptrp; unsigned char *outptr = *outptrp; size_t n_convert = MIN (inend - inptr, outend - outptr) / 4; int result;#if __BYTE_ORDER == __LITTLE_ENDIAN /* Sigh, we have to do some real work. */ size_t cnt; for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4) { *((uint32_t *) outptr) = bswap_32 (*(const uint32_t *) inptr); outptr = (unsigned char *)((uint32_t *) outptr + 1); } *inptrp = inptr; *outptrp = outptr;#elif __BYTE_ORDER == __BIG_ENDIAN /* Simply copy the data. */ *inptrp = inptr + n_convert * 4; *outptrp = memcpy (outptr, inptr, n_convert * 4); *outptrp += n_convert * 4;#else# error "This endianess is not supported."#endif /* Determine the status. */ if (*inptrp == inend) result = __GCONV_EMPTY_INPUT; else if (*outptrp + 4 > outend) result = __GCONV_FULL_OUTPUT; else result = __GCONV_INCOMPLETE_INPUT; return result;}#ifndef _STRING_ARCH_unalignedstatic inline intinternal_ucs4_loop_unaligned (struct __gconv_step *step, struct __gconv_step_data *step_data, const unsigned char **inptrp, const unsigned char *inend, unsigned char **outptrp, unsigned char *outend, size_t *irreversible){ const unsigned char *inptr = *inptrp; unsigned char *outptr = *outptrp; size_t n_convert = MIN (inend - inptr, outend - outptr) / 4; int result;# if __BYTE_ORDER == __LITTLE_ENDIAN /* Sigh, we have to do some real work. */ size_t cnt; for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4, outptr += 4) { outptr[0] = inptr[3]; outptr[1] = inptr[2]; outptr[2] = inptr[1]; outptr[3] = inptr[0]; } *inptrp = inptr; *outptrp = outptr;# elif __BYTE_ORDER == __BIG_ENDIAN /* Simply copy the data. */ *inptrp = inptr + n_convert * 4; *outptrp = memcpy (outptr, inptr, n_convert * 4); *outptrp += n_convert * 4;# else# error "This endianess is not supported."# endif /* Determine the status. */ if (*inptrp == inend) result = __GCONV_EMPTY_INPUT; else if (*outptrp + 4 > outend) result = __GCONV_FULL_OUTPUT; else result = __GCONV_INCOMPLETE_INPUT; return result;}#endifstatic inline intinternal_ucs4_loop_single (struct __gconv_step *step, struct __gconv_step_data *step_data, const unsigned char **inptrp, const unsigned char *inend, unsigned char **outptrp, unsigned char *outend, size_t *irreversible){ mbstate_t *state = step_data->__statep; size_t cnt = state->__count & 7; while (*inptrp < inend && cnt < 4) state->__value.__wchb[cnt++] = *(*inptrp)++; if (__builtin_expect (cnt < 4, 0)) { /* Still not enough bytes. Store the ones in the input buffer. */ state->__count &= ~7; state->__count |= cnt; return __GCONV_INCOMPLETE_INPUT; }#if __BYTE_ORDER == __LITTLE_ENDIAN (*outptrp)[0] = state->__value.__wchb[3]; (*outptrp)[1] = state->__value.__wchb[2]; (*outptrp)[2] = state->__value.__wchb[1]; (*outptrp)[3] = state->__value.__wchb[0]; *outptrp += 4;#elif __BYTE_ORDER == __BIG_ENDIAN { uint32_t **p = (uint32_t **)outptrp; uint32_t *q = *p; /* XXX unaligned */ *q = state->__value.__wch; outptrp = (unsigned char *)(p + 1); }#else# error "This endianess is not supported."#endif /* Clear the state buffer. */ state->__count &= ~7; return __GCONV_OK;}#include <iconv/skeleton.c>/* Transform from UCS4 to the internal, UCS4-like format. Unlike for the other direction we have to check for correct values here. */#define DEFINE_INIT 0#define DEFINE_FINI 0#define MIN_NEEDED_FROM 4#define MIN_NEEDED_TO 4#define FROM_DIRECTION 1#define FROM_LOOP ucs4_internal_loop#define TO_LOOP ucs4_internal_loop /* This is not used. */#define FUNCTION_NAME __gconv_transform_ucs4_internalstatic inline intucs4_internal_loop (struct __gconv_step *step, struct __gconv_step_data *step_data, const unsigned char **inptrp, const unsigned char *inend, unsigned char **outptrp, unsigned char *outend, size_t *irreversible){ int flags = step_data->__flags; const unsigned char *inptr = *inptrp; unsigned char *outptr = *outptrp; size_t n_convert = MIN (inend - inptr, outend - outptr) / 4; int result; size_t cnt; for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4) { uint32_t inval;#if __BYTE_ORDER == __LITTLE_ENDIAN inval = bswap_32 (*(const uint32_t *) inptr);#else inval = *(const uint32_t *) inptr;#endif if (__builtin_expect (inval > 0x7fffffff, 0)) { /* The value is too large. We don't try transliteration here since this is not an error because of the lack of possibilities to represent the result. This is a genuine bug in the input since UCS4 does not allow such values. */ if (irreversible == NULL) /* We are transliterating, don't try to correct anything. */ return __GCONV_ILLEGAL_INPUT; if (flags & __GCONV_IGNORE_ERRORS) { /* Just ignore this character. */ *irreversible = *irreversible + 1; continue; } *inptrp = inptr; *outptrp = outptr; return __GCONV_ILLEGAL_INPUT; } *((uint32_t *) outptr) = inval; outptr = (unsigned char *) ((uint32_t *) outptr + 1); } *inptrp = inptr; *outptrp = outptr; /* Determine the status. */ if (*inptrp == inend) result = __GCONV_EMPTY_INPUT; else if (*outptrp + 4 > outend) result = __GCONV_FULL_OUTPUT; else result = __GCONV_INCOMPLETE_INPUT; return result;}#ifndef _STRING_ARCH_unalignedstatic inline intucs4_internal_loop_unaligned (struct __gconv_step *step, struct __gconv_step_data *step_data, const unsigned char **inptrp, const unsigned char *inend, unsigned char **outptrp, unsigned char *outend, size_t *irreversible){ int flags = step_data->__flags; const unsigned char *inptr = *inptrp; unsigned char *outptr = *outptrp; size_t n_convert = MIN (inend - inptr, outend - outptr) / 4; int result; size_t cnt; for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4) { if (__builtin_expect (inptr[0] > 0x80, 0)) { /* The value is too large. We don't try transliteration here since this is not an error because of the lack of possibilities to represent the result. This is a genuine bug in the input since UCS4 does not allow such values. */ if (irreversible == NULL) /* We are transliterating, don't try to correct anything. */ return __GCONV_ILLEGAL_INPUT; if (flags & __GCONV_IGNORE_ERRORS) { /* Just ignore this character. */ *irreversible = *irreversible + 1; continue; } *inptrp = inptr; *outptrp = outptr; return __GCONV_ILLEGAL_INPUT; }# if __BYTE_ORDER == __LITTLE_ENDIAN outptr[3] = inptr[0]; outptr[2] = inptr[1]; outptr[1] = inptr[2]; outptr[0] = inptr[3];# else outptr[0] = inptr[0]; outptr[1] = inptr[1]; outptr[2] = inptr[2]; outptr[3] = inptr[3];# endif outptr += 4; } *inptrp = inptr; *outptrp = outptr; /* Determine the status. */ if (*inptrp == inend) result = __GCONV_EMPTY_INPUT; else if (*outptrp + 4 > outend) result = __GCONV_FULL_OUTPUT; else result = __GCONV_INCOMPLETE_INPUT; return result;}#endifstatic inline intucs4_internal_loop_single (struct __gconv_step *step, struct __gconv_step_data *step_data, const unsigned char **inptrp, const unsigned char *inend, unsigned char **outptrp, unsigned char *outend, size_t *irreversible){ mbstate_t *state = step_data->__statep; int flags = step_data->__flags; size_t cnt = state->__count & 7; while (*inptrp < inend && cnt < 4) state->__value.__wchb[cnt++] = *(*inptrp)++; if (__builtin_expect (cnt < 4, 0)) { /* Still not enough bytes. Store the ones in the input buffer. */ state->__count &= ~7; state->__count |= cnt; return __GCONV_INCOMPLETE_INPUT; } if (__builtin_expect (((unsigned char *) state->__value.__wchb)[0] > 0x80, 0)) { /* The value is too large. We don't try transliteration here since this is not an error because of the lack of possibilities to represent the result. This is a genuine bug in the input since UCS4 does not allow such values. */ if (!(flags & __GCONV_IGNORE_ERRORS)) { *inptrp -= cnt - (state->__count & 7); return __GCONV_ILLEGAL_INPUT; } } else {#if __BYTE_ORDER == __LITTLE_ENDIAN (*outptrp)[0] = state->__value.__wchb[3]; (*outptrp)[1] = state->__value.__wchb[2]; (*outptrp)[2] = state->__value.__wchb[1]; (*outptrp)[3] = state->__value.__wchb[0];#elif __BYTE_ORDER == __BIG_ENDIAN (*outptrp)[0] = state->__value.__wchb[0]; (*outptrp)[1] = state->__value.__wchb[1]; (*outptrp)[2] = state->__value.__wchb[2]; (*outptrp)[3] = state->__value.__wchb[3];#endif *outptrp += 4; } /* Clear the state buffer. */ state->__count &= ~7; return __GCONV_OK;}#include <iconv/skeleton.c>/* Similarly for the little endian form. */#define DEFINE_INIT 0#define DEFINE_FINI 0#define MIN_NEEDED_FROM 4#define MIN_NEEDED_TO 4#define FROM_DIRECTION 1#define FROM_LOOP internal_ucs4le_loop#define TO_LOOP internal_ucs4le_loop /* This is not used. */#define FUNCTION_NAME __gconv_transform_internal_ucs4lestatic inline intinternal_ucs4le_loop (struct __gconv_step *step, struct __gconv_step_data *step_data, const unsigned char **inptrp, const unsigned char *inend, unsigned char **outptrp, unsigned char *outend, size_t *irreversible){ const unsigned char *inptr = *inptrp; unsigned char *outptr = *outptrp; size_t n_convert = MIN (inend - inptr, outend - outptr) / 4; int result;#if __BYTE_ORDER == __BIG_ENDIAN /* Sigh, we have to do some real work. */ size_t cnt; for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4) *((uint32_t *) outptr)++ = bswap_32 (*(const uint32_t *) inptr); *inptrp = inptr; *outptrp = outptr;#elif __BYTE_ORDER == __LITTLE_ENDIAN /* Simply copy the data. */ *inptrp = inptr + n_convert * 4; *outptrp = memcpy (outptr, inptr, n_convert * 4); *outptrp += n_convert * 4;#else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -