From: Nobuyoshi Nakada Date: 2008-01-22T09:05:26+09:00 Subject: [ruby-dev:33271] Re: default encoding for Marshal.load なかだです。 At Tue, 22 Jan 2008 04:59:27 +0900, NARUSE, Yui wrote in [ruby-dev:33268]: > Marlshal.recursive_force_encoding とかいう「データ中の文字列をたどって > force_encoding する」メソッドがあったら楽だろうと思ったんですが、すごい > 面倒そうだったので [ruby-dev:33205] の「dumpの入力データのエンコーディン > グにする」を書いてみました。 > @@ -968,7 +969,7 @@ r_bytes0(long len, struct load_arg *arg) > if (len == 0) return rb_str_new(0, 0); > if (TYPE(arg->src) == T_STRING) { > if (RSTRING_LEN(arg->src) - arg->offset >= len) { > - str = rb_str_new(RSTRING_PTR(arg->src)+arg->offset, len); > + str = rb_enc_str_new(RSTRING_PTR(arg->src)+arg->offset, len, arg->enc); String限定なら、ここでrb_str_subseq()を使うだけでもできます。 それ以外のときが問題で、IO#read(length)は常にASCII-8BITを返すの で入力から調べることもできません。IOにもrb_enc_get()で取れるよう にエンコーディングをセットしておけば簡単なんですけど。 > この arg.enc に encoding をつっこむ方法が何かあれば明示的に指定できるの > ですが、まぁ、これで事実上問題ないのではないでしょうか。 引数なしのMarshal.loadがMarshal::Loaderオブジェクトを返す、とか でしょうか。 Index: marshal.c =================================================================== --- marshal.c (revision 15163) +++ marshal.c (working copy) @@ -81,5 +81,5 @@ shortlen(long len, BDIGIT *ds) static ID s_dump, s_load, s_mdump, s_mload; static ID s_dump_data, s_load_data, s_alloc; -static ID s_getc, s_read, s_write, s_binmode; +static ID s_getc, s_read, s_write, s_binmode, s_external_encoding; ID rb_id_encoding(void); @@ -883,4 +883,5 @@ struct load_arg { st_table *compat_tbl; VALUE compat_tbl_wrapper; + rb_encoding *enc; }; @@ -966,5 +967,5 @@ r_bytes0(long len, struct load_arg *arg) VALUE str; - if (len == 0) return rb_str_new(0, 0); + if (len == 0) return rb_enc_str_new(0, 0, arg->enc); if (TYPE(arg->src) == T_STRING) { if (RSTRING_LEN(arg->src) - arg->offset >= len) { @@ -986,4 +987,5 @@ r_bytes0(long len, struct load_arg *arg) if (OBJ_TAINTED(str)) arg->taint = Qtrue; } + rb_enc_associate(str, arg->enc); return str; } @@ -1553,7 +1555,9 @@ marshal_load(int argc, VALUE *argv) rb_scan_args(argc, argv, "11", &port, &proc); + arg.enc = 0; if (rb_respond_to(port, rb_intern("to_str"))) { arg.taint = OBJ_TAINTED(port); /* original taintedness */ StringValue(port); /* possible conversion */ + arg.enc = rb_enc_get(port); } else if (rb_respond_to(port, s_getc) && rb_respond_to(port, s_read)) { @@ -1561,4 +1565,9 @@ marshal_load(int argc, VALUE *argv) rb_funcall2(port, s_binmode, 0, 0); } + if (rb_respond_to(port, s_external_encoding)) { + VALUE enc = rb_funcall2(port, s_external_encoding, 0, 0); + rb_p(enc); + arg.enc = rb_to_encoding(enc); + } arg.taint = Qtrue; } @@ -1642,4 +1651,5 @@ Init_marshal(void) s_write = rb_intern("write"); s_binmode = rb_intern("binmode"); + s_external_encoding = rb_intern("external_encoding"); rb_define_module_function(rb_mMarshal, "dump", marshal_dump, -1); -- --- 僕の前にBugはない。 --- 僕の後ろにBugはできる。 中田 伸悦