summary refs log tree commit diff
path: root/iconv/gconv_simple.c
diff options
context:
space:
mode:
Diffstat (limited to 'iconv/gconv_simple.c')
-rw-r--r--iconv/gconv_simple.c177
1 files changed, 134 insertions, 43 deletions
diff --git a/iconv/gconv_simple.c b/iconv/gconv_simple.c
index 4b7004caa6..188fc04c0e 100644
--- a/iconv/gconv_simple.c
+++ b/iconv/gconv_simple.c
@@ -19,6 +19,7 @@
    Boston, MA 02111-1307, USA.  */
 
 #include <byteswap.h>
+#include <dlfcn.h>
 #include <endian.h>
 #include <errno.h>
 #include <gconv.h>
@@ -62,9 +63,10 @@ static const unsigned char encoding_byte[] =
 
 
 static inline int
-internal_ucs4_loop (const unsigned char **inptrp, const unsigned char *inend,
+internal_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,
-		    mbstate_t *state, int flags, void *data,
 		    size_t *irreversible)
 {
   const unsigned char *inptr = *inptrp;
@@ -102,10 +104,11 @@ internal_ucs4_loop (const unsigned char **inptrp, const unsigned char *inend,
 
 #ifndef _STRING_ARCH_unaligned
 static inline int
-internal_ucs4_loop_unaligned (const unsigned char **inptrp,
+internal_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,
-			      mbstate_t *state, int flags, void *data,
 			      size_t *irreversible)
 {
   const unsigned char *inptr = *inptrp;
@@ -149,12 +152,14 @@ internal_ucs4_loop_unaligned (const unsigned char **inptrp,
 
 
 static inline int
-internal_ucs4_loop_single (const unsigned char **inptrp,
+internal_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,
-			   mbstate_t *state, int flags, void *data,
 			   size_t *irreversible)
 {
+  mbstate_t *state = step_data->__statep;
   size_t cnt = state->__count & 7;
 
   while (*inptrp < inend && cnt < 4)
@@ -205,11 +210,13 @@ internal_ucs4_loop_single (const unsigned char **inptrp,
 
 
 static inline int
-ucs4_internal_loop (const unsigned char **inptrp, const unsigned char *inend,
+ucs4_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,
-		    mbstate_t *state, int flags, void *data,
 		    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;
@@ -228,6 +235,10 @@ ucs4_internal_loop (const unsigned char **inptrp, const unsigned char *inend,
 
       if (__builtin_expect (inval, 0) > 0x7fffffff)
 	{
+	  /* 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)
 	    {
 	      /* Just ignore this character.  */
@@ -259,23 +270,28 @@ ucs4_internal_loop (const unsigned char **inptrp, const unsigned char *inend,
 
 #ifndef _STRING_ARCH_unaligned
 static inline int
-ucs4_internal_loop_unaligned (const unsigned char **inptrp,
+ucs4_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,
-			      mbstate_t *state, int flags, void *data,
 			      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, outptr += 4)
+  for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4)
     {
       if (__builtin_expect (inptr[0], 0) > 0x80)
 	{
-	  /* The value is too large.  */
+	  /* 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)
 	    {
 	      /* Just ignore this character.  */
@@ -299,6 +315,7 @@ ucs4_internal_loop_unaligned (const unsigned char **inptrp,
       outptr[2] = inptr[2];
       outptr[3] = inptr[3];
 # endif
+      outptr += 4;
     }
 
   *inptrp = inptr;
@@ -318,12 +335,15 @@ ucs4_internal_loop_unaligned (const unsigned char **inptrp,
 
 
 static inline int
-ucs4_internal_loop_single (const unsigned char **inptrp,
+ucs4_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,
-			   mbstate_t *state, int flags, void *data,
 			   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)
@@ -341,7 +361,10 @@ ucs4_internal_loop_single (const unsigned char **inptrp,
   if (__builtin_expect (((unsigned char *) state->__value.__wchb)[0], 0)
       > 0x80)
     {
-      /* The value is too large.  */
+      /* 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);
@@ -386,9 +409,10 @@ ucs4_internal_loop_single (const unsigned char **inptrp,
 
 
 static inline int
-internal_ucs4le_loop (const unsigned char **inptrp, const unsigned char *inend,
+internal_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,
-		      mbstate_t *state, int flags, void *data,
 		      size_t *irreversible)
 {
   const unsigned char *inptr = *inptrp;
@@ -426,10 +450,11 @@ internal_ucs4le_loop (const unsigned char **inptrp, const unsigned char *inend,
 
 #ifndef _STRING_ARCH_unaligned
 static inline int
-internal_ucs4le_loop_unaligned (const unsigned char **inptrp,
+internal_ucs4le_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,
-				mbstate_t *state, int flags, void *data,
 				size_t *irreversible)
 {
   const unsigned char *inptr = *inptrp;
@@ -473,12 +498,14 @@ internal_ucs4le_loop_unaligned (const unsigned char **inptrp,
 
 
 static inline int
-internal_ucs4le_loop_single (const unsigned char **inptrp,
+internal_ucs4le_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,
-			     mbstate_t *state, int flags, void *data,
 			     size_t *irreversible)
 {
+  mbstate_t *state = step_data->__statep;
   size_t cnt = state->__count & 7;
 
   while (*inptrp < inend && cnt < 4)
@@ -526,11 +553,13 @@ internal_ucs4le_loop_single (const unsigned char **inptrp,
 
 
 static inline int
-ucs4le_internal_loop (const unsigned char **inptrp, const unsigned char *inend,
+ucs4le_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,
-		      mbstate_t *state, int flags, void *data,
 		      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;
@@ -549,6 +578,10 @@ ucs4le_internal_loop (const unsigned char **inptrp, const unsigned char *inend,
 
       if (__builtin_expect (inval, 0) > 0x7fffffff)
 	{
+	  /* 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)
 	    {
 	      /* Just ignore this character.  */
@@ -578,12 +611,14 @@ ucs4le_internal_loop (const unsigned char **inptrp, const unsigned char *inend,
 
 #ifndef _STRING_ARCH_unaligned
 static inline int
-ucs4le_internal_loop_unaligned (const unsigned char **inptrp,
+ucs4le_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,
-				mbstate_t *state, int flags, void *data,
 				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;
@@ -594,7 +629,10 @@ ucs4le_internal_loop_unaligned (const unsigned char **inptrp,
     {
       if (__builtin_expect (inptr[3], 0) > 0x80)
 	{
-	  /* The value is too large.  */
+	  /* 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)
 	    {
 	      /* Just ignore this character.  */
@@ -639,12 +677,15 @@ ucs4le_internal_loop_unaligned (const unsigned char **inptrp,
 
 
 static inline int
-ucs4le_internal_loop_single (const unsigned char **inptrp,
+ucs4le_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,
-			     mbstate_t *state, int flags, void *data,
 			     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)
@@ -662,7 +703,10 @@ ucs4le_internal_loop_single (const unsigned char **inptrp,
   if (__builtin_expect (((unsigned char *) state->__value.__wchb)[3], 0)
       > 0x80)
     {
-      /* The value is too large.  */
+      /* 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))
 	return __GCONV_ILLEGAL_INPUT;
     }
@@ -710,6 +754,10 @@ ucs4le_internal_loop_single (const unsigned char **inptrp,
   {									      \
     if (__builtin_expect (*inptr, 0) > '\x7f')				      \
       {									      \
+	/* 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    \
+	   ASCII does not allow such values.  */			      \
 	if (! ignore_errors_p ())					      \
 	  {								      \
 	    /* This is no correct ANSI_X3.4-1968 character.  */		      \
@@ -718,13 +766,14 @@ ucs4le_internal_loop_single (const unsigned char **inptrp,
 	  }								      \
 									      \
 	++*irreversible;						      \
-	++inptr; 							      \
+	++inptr;							      \
       }									      \
     else								      \
       /* It's an one byte sequence.  */					      \
       /* XXX unaligned.  */						      \
       *((uint32_t *) outptr)++ = *inptr++;				      \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 #include <iconv/skeleton.c>
 
@@ -740,6 +789,13 @@ ucs4le_internal_loop_single (const unsigned char **inptrp,
 #define FUNCTION_NAME		__gconv_transform_internal_ascii
 #define ONE_DIRECTION		1
 
+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);
+
 #define MIN_NEEDED_INPUT	MIN_NEEDED_FROM
 #define MIN_NEEDED_OUTPUT	MIN_NEEDED_TO
 #define LOOPFCT			FROM_LOOP
@@ -748,20 +804,31 @@ ucs4le_internal_loop_single (const unsigned char **inptrp,
     /* XXX unaligned.  */						      \
     if (__builtin_expect (*((uint32_t *) inptr), 0) > 0x7f)		      \
       {									      \
-	if (! ignore_errors_p ())					      \
+	if (step_data->__trans.__trans_fct != NULL)			      \
+	  {								      \
+	    result = DL_CALL_FCT (step_data->__trans.__trans_fct,	      \
+				  (step, step_data, *inptrp, &inptr, inend,   \
+				   *outptrp, &outptr, outend, irreversible)); \
+	    if (result != __GCONV_OK)					      \
+	      break;							      \
+	  }								      \
+	else if (! ignore_errors_p ())					      \
 	  {								      \
 	    /* This is no correct ANSI_X3.4-1968 character.  */		      \
 	    result = __GCONV_ILLEGAL_INPUT;				      \
 	    break;							      \
 	  }								      \
-									      \
-	++*irreversible;						      \
-	inptr += 4; 							      \
+	else								      \
+	  {								      \
+	    ++*irreversible;						      \
+	    inptr += 4; 						      \
+	  }								      \
       }									      \
     else								      \
       /* It's an one byte sequence.  */					      \
       *outptr++ = *((uint32_t *) inptr)++;				      \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 #include <iconv/skeleton.c>
 
@@ -916,7 +983,7 @@ ucs4le_internal_loop_single (const unsigned char **inptrp,
 	     continue;							      \
 	  }								      \
 									      \
-	if (NEED_LENGTH_TEST && __builtin_expect (inptr + cnt > inend, 0))    \
+	if (__builtin_expect (inptr + cnt > inend, 0))			    \
 	  {								      \
 	    /* We don't have enough input.  But before we report that check   \
 	       that all the bytes are correct.  */			      \
@@ -979,6 +1046,7 @@ ucs4le_internal_loop_single (const unsigned char **inptrp,
     /* Now adjust the pointers and store the result.  */		      \
     *((uint32_t *) outptr)++ = ch;					      \
   }
+#define LOOP_NEED_FLAGS
 
 #define STORE_REST \
   {									      \
@@ -1125,18 +1193,29 @@ ucs4le_internal_loop_single (const unsigned char **inptrp,
   {									      \
     if (__builtin_expect (*((uint32_t *) inptr), 0) >= 0x10000)		      \
       {									      \
-	if (! ignore_errors_p ())					      \
+	if (step_data->__trans.__trans_fct != NULL)			      \
+	  {								      \
+	    result = DL_CALL_FCT (step_data->__trans.__trans_fct,	      \
+				  (step, step_data, *inptrp, &inptr, inend,   \
+				   *outptrp, &outptr, outend, irreversible)); \
+	    if (result != __GCONV_OK)					      \
+	      break;							      \
+	  }								      \
+	else if (! ignore_errors_p ())					      \
 	  {								      \
 	    result = __GCONV_ILLEGAL_INPUT;				      \
 	    break;							      \
 	  }								      \
-									      \
-	inptr += 4;							      \
-	++*irreversible;						      \
+	else								      \
+	  {								      \
+	    inptr += 4;							      \
+	    ++*irreversible;						      \
+	  }								      \
       }									      \
     else 								      \
       *((uint16_t *) outptr)++ = *((uint32_t *) inptr)++;		      \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 #include <iconv/skeleton.c>
 
@@ -1181,17 +1260,29 @@ ucs4le_internal_loop_single (const unsigned char **inptrp,
     uint32_t val = *((uint32_t *) inptr);				      \
     if (__builtin_expect (val, 0) >= 0x10000)				      \
       {									      \
-	if (! ignore_errors_p ())					      \
+	if (step_data->__trans.__trans_fct != NULL)			      \
+	  {								      \
+	    result = DL_CALL_FCT (step_data->__trans.__trans_fct,	      \
+				  (step, step_data, *inptrp, &inptr, inend,   \
+				   *outptrp, &outptr, outend, irreversible)); \
+	    if (result != __GCONV_OK)					      \
+	      break;							      \
+	  }								      \
+	else if (! ignore_errors_p ())					      \
 	  {								      \
 	    result = __GCONV_ILLEGAL_INPUT;				      \
 	    break;							      \
 	  }								      \
-									      \
-	inptr += 4;							      \
-	++*irreversible;						      \
+	else								      \
+	  {								      \
+	    inptr += 4;							      \
+	    ++*irreversible;						      \
+	  }								      \
+	continue;							      \
       }									      \
     *((uint16_t *) outptr)++ = bswap_16 (val);				      \
     inptr += 4;								      \
   }
+#define LOOP_NEED_FLAGS
 #include <iconv/loop.c>
 #include <iconv/skeleton.c>