@@ -1026,14 +1026,14 @@ trans_open_i(const char *sname, const char *dname, int depth, void *arg)
10261026}
10271027
10281028static rb_econv_t *
1029- rb_econv_open0 (const char * sname , const char * dname , int ecflags )
1029+ rb_econv_open0 (rb_encoding * senc , const char * sname , rb_encoding * denc , const char * dname , int ecflags )
10301030{
10311031 transcoder_entry_t * * entries = NULL ;
10321032 int num_trans ;
10331033 rb_econv_t * ec ;
10341034
1035- if (* sname ) rb_enc_find_index (sname ); // loads encoding if not already loaded
1036- if (* dname ) rb_enc_find_index (dname ); // loads encoding if not already loaded
1035+ if (* sname && (! senc || ! senc -> max_enc_len ) ) rb_enc_find_index (sname ); // loads encoding if not already loaded
1036+ if (* dname && (! denc || ! denc -> max_enc_len ) ) rb_enc_find_index (dname ); // loads encoding if not already loaded
10371037
10381038 if (* sname == '\0' && * dname == '\0' ) {
10391039 num_trans = 0 ;
@@ -1127,6 +1127,35 @@ decorator_names(int ecflags, const char **decorators_ret)
11271127 return num_decorators ;
11281128}
11291129
1130+ static rb_econv_t *
1131+ rb_econv_open_enc (rb_encoding * senc , const char * sname , rb_encoding * denc , const char * dname , int ecflags )
1132+ {
1133+ rb_econv_t * ec ;
1134+ int num_decorators ;
1135+ const char * decorators [MAX_ECFLAGS_DECORATORS ];
1136+ int i ;
1137+
1138+ num_decorators = decorator_names (ecflags , decorators );
1139+ if (num_decorators == -1 )
1140+ return NULL ;
1141+
1142+ ec = rb_econv_open0 (senc , sname , denc , dname , ecflags & ECONV_ERROR_HANDLER_MASK );
1143+ if (ec ) {
1144+ for (i = 0 ; i < num_decorators ; i ++ ) {
1145+ if (rb_econv_decorate_at_last (ec , decorators [i ]) == -1 ) {
1146+ rb_econv_close (ec );
1147+ ec = NULL ;
1148+ break ;
1149+ }
1150+ }
1151+ }
1152+
1153+ if (ec ) {
1154+ ec -> flags |= ecflags & ~ECONV_ERROR_HANDLER_MASK ;
1155+ }
1156+ return ec ; // can be NULL
1157+ }
1158+
11301159rb_econv_t *
11311160rb_econv_open (const char * sname , const char * dname , int ecflags )
11321161{
@@ -1139,7 +1168,7 @@ rb_econv_open(const char *sname, const char *dname, int ecflags)
11391168 if (num_decorators == -1 )
11401169 return NULL ;
11411170
1142- ec = rb_econv_open0 (sname , dname , ecflags & ECONV_ERROR_HANDLER_MASK );
1171+ ec = rb_econv_open0 (NULL , sname , NULL , dname , ecflags & ECONV_ERROR_HANDLER_MASK );
11431172 if (ec ) {
11441173 for (i = 0 ; i < num_decorators ; i ++ ) {
11451174 if (rb_econv_decorate_at_last (ec , decorators [i ]) == -1 ) {
@@ -2360,11 +2389,16 @@ aref_fallback(VALUE fallback, VALUE c)
23602389 return rb_funcallv_public (fallback , idAREF , 1 , & c );
23612390}
23622391
2392+ static rb_econv_t *
2393+ rb_econv_open_opts_enc (rb_encoding * senc , const char * source_encoding , rb_encoding * denc , const char * destination_encoding , int ecflags , VALUE opthash );
2394+
23632395static void
23642396transcode_loop (const unsigned char * * in_pos , unsigned char * * out_pos ,
23652397 const unsigned char * in_stop , unsigned char * out_stop ,
23662398 VALUE destination ,
23672399 unsigned char * (* resize_destination )(VALUE , size_t , size_t ),
2400+ rb_encoding * senc ,
2401+ rb_encoding * denc ,
23682402 const char * src_encoding ,
23692403 const char * dst_encoding ,
23702404 int ecflags ,
@@ -2379,7 +2413,7 @@ transcode_loop(const unsigned char **in_pos, unsigned char **out_pos,
23792413 VALUE fallback = Qnil ;
23802414 VALUE (* fallback_func )(VALUE , VALUE ) = 0 ;
23812415
2382- ec = rb_econv_open_opts ( src_encoding , dst_encoding , ecflags , ecopts );
2416+ ec = rb_econv_open_opts_enc ( senc , src_encoding , denc , dst_encoding , ecflags , ecopts );
23832417 if (!ec )
23842418 rb_exc_raise (rb_econv_open_exc (src_encoding , dst_encoding , ecflags ));
23852419
@@ -2684,6 +2718,40 @@ rb_econv_prepare_opts(VALUE opthash, VALUE *opts)
26842718 return rb_econv_prepare_options (opthash , opts , 0 );
26852719}
26862720
2721+ static rb_econv_t *
2722+ rb_econv_open_opts_enc (rb_encoding * senc , const char * source_encoding , rb_encoding * denc , const char * destination_encoding , int ecflags , VALUE opthash )
2723+ {
2724+ rb_econv_t * ec ;
2725+ VALUE replacement ;
2726+
2727+ if (NIL_P (opthash )) {
2728+ replacement = Qnil ;
2729+ }
2730+ else {
2731+ if (!RB_TYPE_P (opthash , T_HASH ) || !OBJ_FROZEN (opthash ))
2732+ rb_bug ("rb_econv_open_opts called with invalid opthash" );
2733+ replacement = rb_hash_aref (opthash , sym_replace );
2734+ }
2735+
2736+ ec = rb_econv_open_enc (senc , source_encoding , denc , destination_encoding , ecflags );
2737+ if (ec ) {
2738+ if (!NIL_P (replacement )) {
2739+ int ret ;
2740+ rb_encoding * enc = rb_enc_get (replacement );
2741+
2742+ ret = rb_econv_set_replacement (ec ,
2743+ (const unsigned char * )RSTRING_PTR (replacement ),
2744+ RSTRING_LEN (replacement ),
2745+ rb_enc_name (enc ));
2746+ if (ret == -1 ) {
2747+ rb_econv_close (ec );
2748+ ec = NULL ;
2749+ }
2750+ }
2751+ }
2752+ return ec ; // can be NULL
2753+ }
2754+
26872755rb_econv_t *
26882756rb_econv_open_opts (const char * source_encoding , const char * destination_encoding , int ecflags , VALUE opthash )
26892757{
@@ -2778,7 +2846,7 @@ str_transcode0(int argc, VALUE *argv, VALUE *self, int ecflags, VALUE ecopts)
27782846 long blen , slen ;
27792847 unsigned char * buf , * bp , * sp ;
27802848 const unsigned char * fromp ;
2781- rb_encoding * senc , * denc ;
2849+ rb_encoding * senc = NULL , * denc = NULL ;
27822850 const char * sname , * dname ;
27832851 int dencidx ;
27842852 int explicitly_invalid_replace = TRUE;
@@ -2847,7 +2915,7 @@ str_transcode0(int argc, VALUE *argv, VALUE *self, int ecflags, VALUE ecopts)
28472915 dest = rb_str_tmp_new (blen );
28482916 bp = (unsigned char * )RSTRING_PTR (dest );
28492917
2850- transcode_loop (& fromp , & bp , (sp + slen ), (bp + blen ), dest , str_transcoding_resize , sname , dname , ecflags , ecopts );
2918+ transcode_loop (& fromp , & bp , (sp + slen ), (bp + blen ), dest , str_transcoding_resize , senc , denc , sname , dname , ecflags , ecopts );
28512919 if (fromp != sp + slen ) {
28522920 rb_raise (rb_eArgError , "not fully converted, %" PRIdPTRDIFF " bytes left" , sp + slen - fromp );
28532921 }
0 commit comments