Bug #8445 » support-fallback-for-io.patch
transcode.c (作業コピー) | ||
---|---|---|
size_t readagain_len;
|
||
} last_error;
|
||
VALUE fallback;
|
||
VALUE (*fallback_func)(VALUE, VALUE);
|
||
/* The following fields are only for Encoding::Converter.
|
||
* rb_econv_open set them NULL. */
|
||
rb_encoding *source_encoding;
|
||
rb_encoding *destination_encoding;
|
||
};
|
||
/*
|
||
... | ... | |
ec->last_error.readagain_len = 0;
|
||
ec->source_encoding = NULL;
|
||
ec->destination_encoding = NULL;
|
||
ec->fallback = Qnil;
|
||
ec->fallback_func = 0;
|
||
return ec;
|
||
}
|
||
... | ... | |
resume:
|
||
ret = rb_econv_convert0(ec, input_ptr, input_stop, output_ptr, output_stop, flags);
|
||
if (!NIL_P(ec->fallback) && ret == econv_undefined_conversion) {
|
||
VALUE rep = rb_enc_str_new(
|
||
(const char *)ec->last_error.error_bytes_start,
|
||
ec->last_error.error_bytes_len,
|
||
rb_enc_find(ec->last_error.source_encoding));
|
||
rep = (*(ec->fallback_func))(ec->fallback, rep);
|
||
if (rep != Qundef && !NIL_P(rep)) {
|
||
StringValue(rep);
|
||
ret = rb_econv_insert_output(ec, (const unsigned char *)RSTRING_PTR(rep),
|
||
RSTRING_LEN(rep), rb_enc_name(rb_enc_get(rep)));
|
||
if ((int)ret == -1) {
|
||
rb_raise(rb_eArgError, "too big fallback string");
|
||
}
|
||
goto resume;
|
||
}
|
||
}
|
||
if (ret == econv_invalid_byte_sequence ||
|
||
ret == econv_incomplete_input) {
|
||
/* deal with invalid byte sequence */
|
||
... | ... | |
unsigned char *out_start = *out_pos;
|
||
int max_output;
|
||
VALUE exc;
|
||
VALUE fallback = Qnil;
|
||
VALUE (*fallback_func)(VALUE, VALUE) = 0;
|
||
ec = rb_econv_open_opts(src_encoding, dst_encoding, ecflags, ecopts);
|
||
if (!ec)
|
||
rb_exc_raise(rb_econv_open_exc(src_encoding, dst_encoding, ecflags));
|
||
if (!NIL_P(ecopts) && RB_TYPE_P(ecopts, T_HASH)) {
|
||
fallback = rb_hash_aref(ecopts, sym_fallback);
|
||
if (RB_TYPE_P(fallback, T_HASH)) {
|
||
fallback_func = hash_fallback;
|
||
}
|
||
else if (rb_obj_is_proc(fallback)) {
|
||
fallback_func = proc_fallback;
|
||
}
|
||
else if (rb_obj_is_method(fallback)) {
|
||
fallback_func = method_fallback;
|
||
}
|
||
else {
|
||
fallback_func = aref_fallback;
|
||
}
|
||
}
|
||
last_tc = ec->last_tc;
|
||
max_output = last_tc ? last_tc->transcoder->max_output : 1;
|
||
resume:
|
||
ret = rb_econv_convert(ec, in_pos, in_stop, out_pos, out_stop, 0);
|
||
if (!NIL_P(fallback) && ret == econv_undefined_conversion) {
|
||
VALUE rep = rb_enc_str_new(
|
||
(const char *)ec->last_error.error_bytes_start,
|
||
ec->last_error.error_bytes_len,
|
||
rb_enc_find(ec->last_error.source_encoding));
|
||
rep = (*fallback_func)(fallback, rep);
|
||
if (rep != Qundef && !NIL_P(rep)) {
|
||
StringValue(rep);
|
||
ret = rb_econv_insert_output(ec, (const unsigned char *)RSTRING_PTR(rep),
|
||
RSTRING_LEN(rep), rb_enc_name(rb_enc_get(rep)));
|
||
if ((int)ret == -1) {
|
||
rb_raise(rb_eArgError, "too big fallback string");
|
||
}
|
||
goto resume;
|
||
}
|
||
}
|
||
if (ret == econv_invalid_byte_sequence ||
|
||
ret == econv_incomplete_input ||
|
||
ret == econv_undefined_conversion) {
|
||
... | ... | |
{
|
||
rb_econv_t *ec;
|
||
VALUE replacement;
|
||
VALUE fallback = Qnil;
|
||
VALUE (*fallback_func)(VALUE, VALUE) = 0;
|
||
if (NIL_P(opthash)) {
|
||
replacement = Qnil;
|
||
... | ... | |
return NULL;
|
||
}
|
||
}
|
||
if (!NIL_P(opthash) && RB_TYPE_P(opthash, T_HASH)) {
|
||
fallback = rb_hash_aref(opthash, sym_fallback);
|
||
if (RB_TYPE_P(fallback, T_HASH)) {
|
||
fallback_func = hash_fallback;
|
||
}
|
||
else if (rb_obj_is_proc(fallback)) {
|
||
fallback_func = proc_fallback;
|
||
}
|
||
else if (rb_obj_is_method(fallback)) {
|
||
fallback_func = method_fallback;
|
||
}
|
||
else {
|
||
fallback_func = aref_fallback;
|
||
}
|
||
ec->fallback = fallback;
|
||
ec->fallback_func = fallback_func;
|
||
}
|
||
return ec;
|
||
}
|
||