convert with one converter
* string.c (rb_str_conv_enc_opts): convert with one converter, instead of re-creating converters for each buffer expansion. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@39822 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
29dc980e65
commit
10f5312de0
@ -1,3 +1,8 @@
|
|||||||
|
Tue Mar 19 17:09:30 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||||
|
|
||||||
|
* string.c (rb_str_conv_enc_opts): convert with one converter, instead
|
||||||
|
of re-creating converters for each buffer expansion.
|
||||||
|
|
||||||
Tue Mar 19 17:06:50 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
Tue Mar 19 17:06:50 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||||
|
|
||||||
* dir.c (glob_helper): compose HFS file names from UTF8-MAC.
|
* dir.c (glob_helper): compose HFS file names from UTF8-MAC.
|
||||||
|
46
string.c
46
string.c
@ -492,12 +492,15 @@ RUBY_ALIAS_FUNCTION(rb_tainted_str_new2(const char *ptr), rb_tainted_str_new_cst
|
|||||||
VALUE
|
VALUE
|
||||||
rb_str_conv_enc_opts(VALUE str, rb_encoding *from, rb_encoding *to, int ecflags, VALUE ecopts)
|
rb_str_conv_enc_opts(VALUE str, rb_encoding *from, rb_encoding *to, int ecflags, VALUE ecopts)
|
||||||
{
|
{
|
||||||
|
extern VALUE rb_cEncodingConverter;
|
||||||
rb_econv_t *ec;
|
rb_econv_t *ec;
|
||||||
rb_econv_result_t ret;
|
rb_econv_result_t ret;
|
||||||
long len;
|
long len, olen;
|
||||||
|
VALUE econv_wrapper;
|
||||||
VALUE newstr;
|
VALUE newstr;
|
||||||
const unsigned char *sp;
|
const unsigned char *start, *sp;
|
||||||
unsigned char *dp;
|
unsigned char *dest, *dp;
|
||||||
|
size_t converted_output = 0;
|
||||||
|
|
||||||
if (!to) return str;
|
if (!to) return str;
|
||||||
if (!from) from = rb_enc_get(str);
|
if (!from) from = rb_enc_get(str);
|
||||||
@ -513,23 +516,38 @@ rb_str_conv_enc_opts(VALUE str, rb_encoding *from, rb_encoding *to, int ecflags,
|
|||||||
|
|
||||||
len = RSTRING_LEN(str);
|
len = RSTRING_LEN(str);
|
||||||
newstr = rb_str_new(0, len);
|
newstr = rb_str_new(0, len);
|
||||||
|
olen = len;
|
||||||
|
|
||||||
retry:
|
|
||||||
ec = rb_econv_open_opts(from->name, to->name, ecflags, ecopts);
|
ec = rb_econv_open_opts(from->name, to->name, ecflags, ecopts);
|
||||||
if (!ec) return str;
|
if (!ec) return str;
|
||||||
|
econv_wrapper = rb_obj_alloc(rb_cEncodingConverter);
|
||||||
|
DATA_PTR(econv_wrapper) = ec;
|
||||||
|
|
||||||
sp = (unsigned char*)RSTRING_PTR(str);
|
sp = (unsigned char*)RSTRING_PTR(str);
|
||||||
dp = (unsigned char*)RSTRING_PTR(newstr);
|
start = sp;
|
||||||
ret = rb_econv_convert(ec, &sp, (unsigned char*)RSTRING_END(str),
|
while ((dest = (unsigned char*)RSTRING_PTR(newstr)),
|
||||||
&dp, (unsigned char*)RSTRING_END(newstr), 0);
|
(dp = dest + converted_output),
|
||||||
rb_econv_close(ec);
|
(ret = rb_econv_convert(ec, &sp, start + len, &dp, dest + olen, 0)),
|
||||||
switch (ret) {
|
ret == econv_destination_buffer_full) {
|
||||||
case econv_destination_buffer_full:
|
|
||||||
/* destination buffer short */
|
/* destination buffer short */
|
||||||
len = len < 2 ? 2 : len * 2;
|
size_t converted_input = sp - start;
|
||||||
rb_str_resize(newstr, len);
|
size_t rest = len - converted_input;
|
||||||
goto retry;
|
converted_output = dp - dest;
|
||||||
|
rb_str_set_len(newstr, converted_output);
|
||||||
|
if (converted_input && converted_output &&
|
||||||
|
rest < (LONG_MAX / converted_output)) {
|
||||||
|
rest = (rest * converted_output) / converted_input;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rest = olen;
|
||||||
|
}
|
||||||
|
olen += rest < 2 ? 2 : rest;
|
||||||
|
rb_str_resize(newstr, olen);
|
||||||
|
}
|
||||||
|
DATA_PTR(econv_wrapper) = 0;
|
||||||
|
rb_econv_close(ec);
|
||||||
|
rb_gc_force_recycle(econv_wrapper);
|
||||||
|
switch (ret) {
|
||||||
case econv_finished:
|
case econv_finished:
|
||||||
len = dp - (unsigned char*)RSTRING_PTR(newstr);
|
len = dp - (unsigned char*)RSTRING_PTR(newstr);
|
||||||
rb_str_set_len(newstr, len);
|
rb_str_set_len(newstr, len);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user