00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include "ruby/ruby.h"
00013 #include "ruby/encoding.h"
00014 #include "internal.h"
00015 #include "transcode_data.h"
00016 #include <ctype.h>
00017
00018 #define ENABLE_ECONV_NEWLINE_OPTION 1
00019
00020
00021 VALUE rb_eUndefinedConversionError;
00022 VALUE rb_eInvalidByteSequenceError;
00023 VALUE rb_eConverterNotFoundError;
00024
00025 VALUE rb_cEncodingConverter;
00026
00027 static VALUE sym_invalid, sym_undef, sym_replace, sym_fallback, sym_aref;
00028 static VALUE sym_xml, sym_text, sym_attr;
00029 static VALUE sym_universal_newline;
00030 static VALUE sym_crlf_newline;
00031 static VALUE sym_cr_newline;
00032 #ifdef ENABLE_ECONV_NEWLINE_OPTION
00033 static VALUE sym_newline, sym_universal, sym_crlf, sym_cr, sym_lf;
00034 #endif
00035 static VALUE sym_partial_input;
00036
00037 static VALUE sym_invalid_byte_sequence;
00038 static VALUE sym_undefined_conversion;
00039 static VALUE sym_destination_buffer_full;
00040 static VALUE sym_source_buffer_empty;
00041 static VALUE sym_finished;
00042 static VALUE sym_after_output;
00043 static VALUE sym_incomplete_input;
00044
00045 static unsigned char *
00046 allocate_converted_string(const char *sname, const char *dname,
00047 const unsigned char *str, size_t len,
00048 unsigned char *caller_dst_buf, size_t caller_dst_bufsize,
00049 size_t *dst_len_ptr);
00050
00051
00052
00053 typedef struct rb_transcoding {
00054 const rb_transcoder *transcoder;
00055
00056 int flags;
00057
00058 int resume_position;
00059 unsigned int next_table;
00060 VALUE next_info;
00061 unsigned char next_byte;
00062 unsigned int output_index;
00063
00064 ssize_t recognized_len;
00065 ssize_t readagain_len;
00066 union {
00067 unsigned char ary[8];
00068 unsigned char *ptr;
00069 } readbuf;
00070
00071 ssize_t writebuf_off;
00072 ssize_t writebuf_len;
00073 union {
00074 unsigned char ary[8];
00075 unsigned char *ptr;
00076 } writebuf;
00077
00078 union rb_transcoding_state_t {
00079 void *ptr;
00080 char ary[sizeof(double) > sizeof(void*) ? sizeof(double) : sizeof(void*)];
00081 double dummy_for_alignment;
00082 } state;
00083 } rb_transcoding;
00084 #define TRANSCODING_READBUF(tc) \
00085 ((tc)->transcoder->max_input <= (int)sizeof((tc)->readbuf.ary) ? \
00086 (tc)->readbuf.ary : \
00087 (tc)->readbuf.ptr)
00088 #define TRANSCODING_WRITEBUF(tc) \
00089 ((tc)->transcoder->max_output <= (int)sizeof((tc)->writebuf.ary) ? \
00090 (tc)->writebuf.ary : \
00091 (tc)->writebuf.ptr)
00092 #define TRANSCODING_WRITEBUF_SIZE(tc) \
00093 ((tc)->transcoder->max_output <= (int)sizeof((tc)->writebuf.ary) ? \
00094 sizeof((tc)->writebuf.ary) : \
00095 (size_t)(tc)->transcoder->max_output)
00096 #define TRANSCODING_STATE_EMBED_MAX ((int)sizeof(union rb_transcoding_state_t))
00097 #define TRANSCODING_STATE(tc) \
00098 ((tc)->transcoder->state_size <= (int)sizeof((tc)->state) ? \
00099 (tc)->state.ary : \
00100 (tc)->state.ptr)
00101
00102 typedef struct {
00103 struct rb_transcoding *tc;
00104 unsigned char *out_buf_start;
00105 unsigned char *out_data_start;
00106 unsigned char *out_data_end;
00107 unsigned char *out_buf_end;
00108 rb_econv_result_t last_result;
00109 } rb_econv_elem_t;
00110
00111 struct rb_econv_t {
00112 int flags;
00113 const char *source_encoding_name;
00114 const char *destination_encoding_name;
00115
00116 int started;
00117
00118 const unsigned char *replacement_str;
00119 size_t replacement_len;
00120 const char *replacement_enc;
00121 int replacement_allocated;
00122
00123 unsigned char *in_buf_start;
00124 unsigned char *in_data_start;
00125 unsigned char *in_data_end;
00126 unsigned char *in_buf_end;
00127 rb_econv_elem_t *elems;
00128 int num_allocated;
00129 int num_trans;
00130 int num_finished;
00131 struct rb_transcoding *last_tc;
00132
00133
00134 struct {
00135 rb_econv_result_t result;
00136 struct rb_transcoding *error_tc;
00137 const char *source_encoding;
00138 const char *destination_encoding;
00139 const unsigned char *error_bytes_start;
00140 size_t error_bytes_len;
00141 size_t readagain_len;
00142 } last_error;
00143
00144
00145
00146 rb_encoding *source_encoding;
00147 rb_encoding *destination_encoding;
00148 };
00149
00150
00151
00152
00153
00154 #define DECORATOR_P(sname, dname) (*(sname) == '\0')
00155
00156 typedef struct {
00157 const char *sname;
00158 const char *dname;
00159 const char *lib;
00160 const rb_transcoder *transcoder;
00161 } transcoder_entry_t;
00162
00163 static st_table *transcoder_table;
00164
00165 static transcoder_entry_t *
00166 make_transcoder_entry(const char *sname, const char *dname)
00167 {
00168 st_data_t val;
00169 st_table *table2;
00170
00171 if (!st_lookup(transcoder_table, (st_data_t)sname, &val)) {
00172 val = (st_data_t)st_init_strcasetable();
00173 st_add_direct(transcoder_table, (st_data_t)sname, val);
00174 }
00175 table2 = (st_table *)val;
00176 if (!st_lookup(table2, (st_data_t)dname, &val)) {
00177 transcoder_entry_t *entry = ALLOC(transcoder_entry_t);
00178 entry->sname = sname;
00179 entry->dname = dname;
00180 entry->lib = NULL;
00181 entry->transcoder = NULL;
00182 val = (st_data_t)entry;
00183 st_add_direct(table2, (st_data_t)dname, val);
00184 }
00185 return (transcoder_entry_t *)val;
00186 }
00187
00188 static transcoder_entry_t *
00189 get_transcoder_entry(const char *sname, const char *dname)
00190 {
00191 st_data_t val;
00192 st_table *table2;
00193
00194 if (!st_lookup(transcoder_table, (st_data_t)sname, &val)) {
00195 return NULL;
00196 }
00197 table2 = (st_table *)val;
00198 if (!st_lookup(table2, (st_data_t)dname, &val)) {
00199 return NULL;
00200 }
00201 return (transcoder_entry_t *)val;
00202 }
00203
00204 void
00205 rb_register_transcoder(const rb_transcoder *tr)
00206 {
00207 const char *const sname = tr->src_encoding;
00208 const char *const dname = tr->dst_encoding;
00209
00210 transcoder_entry_t *entry;
00211
00212 entry = make_transcoder_entry(sname, dname);
00213 if (entry->transcoder) {
00214 rb_raise(rb_eArgError, "transcoder from %s to %s has been already registered",
00215 sname, dname);
00216 }
00217
00218 entry->transcoder = tr;
00219 }
00220
00221 static void
00222 declare_transcoder(const char *sname, const char *dname, const char *lib)
00223 {
00224 transcoder_entry_t *entry;
00225
00226 entry = make_transcoder_entry(sname, dname);
00227 entry->lib = lib;
00228 }
00229
00230 static const char transcoder_lib_prefix[] = "enc/trans/";
00231
00232 void
00233 rb_declare_transcoder(const char *enc1, const char *enc2, const char *lib)
00234 {
00235 if (!lib) {
00236 rb_raise(rb_eArgError, "invalid library name - (null)");
00237 }
00238 declare_transcoder(enc1, enc2, lib);
00239 }
00240
00241 #define encoding_equal(enc1, enc2) (STRCASECMP((enc1), (enc2)) == 0)
00242
00243 typedef struct search_path_queue_tag {
00244 struct search_path_queue_tag *next;
00245 const char *enc;
00246 } search_path_queue_t;
00247
00248 typedef struct {
00249 st_table *visited;
00250 search_path_queue_t *queue;
00251 search_path_queue_t **queue_last_ptr;
00252 const char *base_enc;
00253 } search_path_bfs_t;
00254
00255 static int
00256 transcode_search_path_i(st_data_t key, st_data_t val, st_data_t arg)
00257 {
00258 const char *dname = (const char *)key;
00259 search_path_bfs_t *bfs = (search_path_bfs_t *)arg;
00260 search_path_queue_t *q;
00261
00262 if (st_lookup(bfs->visited, (st_data_t)dname, &val)) {
00263 return ST_CONTINUE;
00264 }
00265
00266 q = ALLOC(search_path_queue_t);
00267 q->enc = dname;
00268 q->next = NULL;
00269 *bfs->queue_last_ptr = q;
00270 bfs->queue_last_ptr = &q->next;
00271
00272 st_add_direct(bfs->visited, (st_data_t)dname, (st_data_t)bfs->base_enc);
00273 return ST_CONTINUE;
00274 }
00275
00276 static int
00277 transcode_search_path(const char *sname, const char *dname,
00278 void (*callback)(const char *sname, const char *dname, int depth, void *arg),
00279 void *arg)
00280 {
00281 search_path_bfs_t bfs;
00282 search_path_queue_t *q;
00283 st_data_t val;
00284 st_table *table2;
00285 int found;
00286 int pathlen = -1;
00287
00288 if (encoding_equal(sname, dname))
00289 return -1;
00290
00291 q = ALLOC(search_path_queue_t);
00292 q->enc = sname;
00293 q->next = NULL;
00294 bfs.queue_last_ptr = &q->next;
00295 bfs.queue = q;
00296
00297 bfs.visited = st_init_strcasetable();
00298 st_add_direct(bfs.visited, (st_data_t)sname, (st_data_t)NULL);
00299
00300 while (bfs.queue) {
00301 q = bfs.queue;
00302 bfs.queue = q->next;
00303 if (!bfs.queue)
00304 bfs.queue_last_ptr = &bfs.queue;
00305
00306 if (!st_lookup(transcoder_table, (st_data_t)q->enc, &val)) {
00307 xfree(q);
00308 continue;
00309 }
00310 table2 = (st_table *)val;
00311
00312 if (st_lookup(table2, (st_data_t)dname, &val)) {
00313 st_add_direct(bfs.visited, (st_data_t)dname, (st_data_t)q->enc);
00314 xfree(q);
00315 found = 1;
00316 goto cleanup;
00317 }
00318
00319 bfs.base_enc = q->enc;
00320 st_foreach(table2, transcode_search_path_i, (st_data_t)&bfs);
00321 bfs.base_enc = NULL;
00322
00323 xfree(q);
00324 }
00325 found = 0;
00326
00327 cleanup:
00328 while (bfs.queue) {
00329 q = bfs.queue;
00330 bfs.queue = q->next;
00331 xfree(q);
00332 }
00333
00334 if (found) {
00335 const char *enc = dname;
00336 int depth;
00337 pathlen = 0;
00338 while (1) {
00339 st_lookup(bfs.visited, (st_data_t)enc, &val);
00340 if (!val)
00341 break;
00342 pathlen++;
00343 enc = (const char *)val;
00344 }
00345 depth = pathlen;
00346 enc = dname;
00347 while (1) {
00348 st_lookup(bfs.visited, (st_data_t)enc, &val);
00349 if (!val)
00350 break;
00351 callback((const char *)val, enc, --depth, arg);
00352 enc = (const char *)val;
00353 }
00354 }
00355
00356 st_free_table(bfs.visited);
00357
00358 return pathlen;
00359 }
00360
00361 static const rb_transcoder *
00362 load_transcoder_entry(transcoder_entry_t *entry)
00363 {
00364 if (entry->transcoder)
00365 return entry->transcoder;
00366
00367 if (entry->lib) {
00368 const char *const lib = entry->lib;
00369 const size_t len = strlen(lib);
00370 const size_t total_len = sizeof(transcoder_lib_prefix) - 1 + len;
00371 const VALUE fn = rb_str_new(0, total_len);
00372 char *const path = RSTRING_PTR(fn);
00373 const int safe = rb_safe_level();
00374
00375 entry->lib = NULL;
00376
00377 memcpy(path, transcoder_lib_prefix, sizeof(transcoder_lib_prefix) - 1);
00378 memcpy(path + sizeof(transcoder_lib_prefix) - 1, lib, len);
00379 rb_str_set_len(fn, total_len);
00380 FL_UNSET(fn, FL_TAINT);
00381 OBJ_FREEZE(fn);
00382 if (!rb_require_safe(fn, safe > 3 ? 3 : safe))
00383 return NULL;
00384 }
00385
00386 if (entry->transcoder)
00387 return entry->transcoder;
00388
00389 return NULL;
00390 }
00391
00392 static const char*
00393 get_replacement_character(const char *encname, size_t *len_ret, const char **repl_encname_ptr)
00394 {
00395 if (encoding_equal(encname, "UTF-8")) {
00396 *len_ret = 3;
00397 *repl_encname_ptr = "UTF-8";
00398 return "\xEF\xBF\xBD";
00399 }
00400 else {
00401 *len_ret = 1;
00402 *repl_encname_ptr = "US-ASCII";
00403 return "?";
00404 }
00405 }
00406
00407
00408
00409
00410
00411 static const unsigned char *
00412 transcode_char_start(rb_transcoding *tc,
00413 const unsigned char *in_start,
00414 const unsigned char *inchar_start,
00415 const unsigned char *in_p,
00416 size_t *char_len_ptr)
00417 {
00418 const unsigned char *ptr;
00419 if (inchar_start - in_start < tc->recognized_len) {
00420 MEMCPY(TRANSCODING_READBUF(tc) + tc->recognized_len,
00421 inchar_start, unsigned char, in_p - inchar_start);
00422 ptr = TRANSCODING_READBUF(tc);
00423 }
00424 else {
00425 ptr = inchar_start - tc->recognized_len;
00426 }
00427 *char_len_ptr = tc->recognized_len + (in_p - inchar_start);
00428 return ptr;
00429 }
00430
00431 static rb_econv_result_t
00432 transcode_restartable0(const unsigned char **in_pos, unsigned char **out_pos,
00433 const unsigned char *in_stop, unsigned char *out_stop,
00434 rb_transcoding *tc,
00435 const int opt)
00436 {
00437 const rb_transcoder *tr = tc->transcoder;
00438 int unitlen = tr->input_unit_length;
00439 ssize_t readagain_len = 0;
00440
00441 const unsigned char *inchar_start;
00442 const unsigned char *in_p;
00443
00444 unsigned char *out_p;
00445
00446 in_p = inchar_start = *in_pos;
00447
00448 out_p = *out_pos;
00449
00450 #define SUSPEND(ret, num) \
00451 do { \
00452 tc->resume_position = (num); \
00453 if (0 < in_p - inchar_start) \
00454 MEMMOVE(TRANSCODING_READBUF(tc)+tc->recognized_len, \
00455 inchar_start, unsigned char, in_p - inchar_start); \
00456 *in_pos = in_p; \
00457 *out_pos = out_p; \
00458 tc->recognized_len += in_p - inchar_start; \
00459 if (readagain_len) { \
00460 tc->recognized_len -= readagain_len; \
00461 tc->readagain_len = readagain_len; \
00462 } \
00463 return (ret); \
00464 resume_label ## num:; \
00465 } while (0)
00466 #define SUSPEND_OBUF(num) \
00467 do { \
00468 while (out_stop - out_p < 1) { SUSPEND(econv_destination_buffer_full, num); } \
00469 } while (0)
00470
00471 #define SUSPEND_AFTER_OUTPUT(num) \
00472 if ((opt & ECONV_AFTER_OUTPUT) && *out_pos != out_p) { \
00473 SUSPEND(econv_after_output, num); \
00474 }
00475
00476 #define next_table (tc->next_table)
00477 #define next_info (tc->next_info)
00478 #define next_byte (tc->next_byte)
00479 #define writebuf_len (tc->writebuf_len)
00480 #define writebuf_off (tc->writebuf_off)
00481
00482 switch (tc->resume_position) {
00483 case 0: break;
00484 case 1: goto resume_label1;
00485 case 2: goto resume_label2;
00486 case 3: goto resume_label3;
00487 case 4: goto resume_label4;
00488 case 5: goto resume_label5;
00489 case 6: goto resume_label6;
00490 case 7: goto resume_label7;
00491 case 8: goto resume_label8;
00492 case 9: goto resume_label9;
00493 case 10: goto resume_label10;
00494 case 11: goto resume_label11;
00495 case 12: goto resume_label12;
00496 case 13: goto resume_label13;
00497 case 14: goto resume_label14;
00498 case 15: goto resume_label15;
00499 case 16: goto resume_label16;
00500 case 17: goto resume_label17;
00501 case 18: goto resume_label18;
00502 case 19: goto resume_label19;
00503 case 20: goto resume_label20;
00504 case 21: goto resume_label21;
00505 case 22: goto resume_label22;
00506 case 23: goto resume_label23;
00507 case 24: goto resume_label24;
00508 case 25: goto resume_label25;
00509 case 26: goto resume_label26;
00510 case 27: goto resume_label27;
00511 case 28: goto resume_label28;
00512 case 29: goto resume_label29;
00513 case 30: goto resume_label30;
00514 case 31: goto resume_label31;
00515 case 32: goto resume_label32;
00516 case 33: goto resume_label33;
00517 case 34: goto resume_label34;
00518 }
00519
00520 while (1) {
00521 inchar_start = in_p;
00522 tc->recognized_len = 0;
00523 next_table = tr->conv_tree_start;
00524
00525 SUSPEND_AFTER_OUTPUT(24);
00526
00527 if (in_stop <= in_p) {
00528 if (!(opt & ECONV_PARTIAL_INPUT))
00529 break;
00530 SUSPEND(econv_source_buffer_empty, 7);
00531 continue;
00532 }
00533
00534 #define BYTE_ADDR(index) (tr->byte_array + (index))
00535 #define WORD_ADDR(index) (tr->word_array + INFO2WORDINDEX(index))
00536 #define BL_BASE BYTE_ADDR(BYTE_LOOKUP_BASE(WORD_ADDR(next_table)))
00537 #define BL_INFO WORD_ADDR(BYTE_LOOKUP_INFO(WORD_ADDR(next_table)))
00538 #define BL_MIN_BYTE (BL_BASE[0])
00539 #define BL_MAX_BYTE (BL_BASE[1])
00540 #define BL_OFFSET(byte) (BL_BASE[2+(byte)-BL_MIN_BYTE])
00541 #define BL_ACTION(byte) (BL_INFO[BL_OFFSET((byte))])
00542
00543 next_byte = (unsigned char)*in_p++;
00544 follow_byte:
00545 if (next_byte < BL_MIN_BYTE || BL_MAX_BYTE < next_byte)
00546 next_info = INVALID;
00547 else {
00548 next_info = (VALUE)BL_ACTION(next_byte);
00549 }
00550 follow_info:
00551 switch (next_info & 0x1F) {
00552 case NOMAP:
00553 {
00554 const unsigned char *p = inchar_start;
00555 writebuf_off = 0;
00556 while (p < in_p) {
00557 TRANSCODING_WRITEBUF(tc)[writebuf_off++] = (unsigned char)*p++;
00558 }
00559 writebuf_len = writebuf_off;
00560 writebuf_off = 0;
00561 while (writebuf_off < writebuf_len) {
00562 SUSPEND_OBUF(3);
00563 *out_p++ = TRANSCODING_WRITEBUF(tc)[writebuf_off++];
00564 }
00565 }
00566 continue;
00567 case 0x00: case 0x04: case 0x08: case 0x0C:
00568 case 0x10: case 0x14: case 0x18: case 0x1C:
00569 SUSPEND_AFTER_OUTPUT(25);
00570 while (in_p >= in_stop) {
00571 if (!(opt & ECONV_PARTIAL_INPUT))
00572 goto incomplete;
00573 SUSPEND(econv_source_buffer_empty, 5);
00574 }
00575 next_byte = (unsigned char)*in_p++;
00576 next_table = (unsigned int)next_info;
00577 goto follow_byte;
00578 case ZERObt:
00579 continue;
00580 case ONEbt:
00581 SUSPEND_OBUF(9); *out_p++ = getBT1(next_info);
00582 continue;
00583 case TWObt:
00584 SUSPEND_OBUF(10); *out_p++ = getBT1(next_info);
00585 SUSPEND_OBUF(21); *out_p++ = getBT2(next_info);
00586 continue;
00587 case THREEbt:
00588 SUSPEND_OBUF(11); *out_p++ = getBT1(next_info);
00589 SUSPEND_OBUF(15); *out_p++ = getBT2(next_info);
00590 SUSPEND_OBUF(16); *out_p++ = getBT3(next_info);
00591 continue;
00592 case FOURbt:
00593 SUSPEND_OBUF(12); *out_p++ = getBT0(next_info);
00594 SUSPEND_OBUF(17); *out_p++ = getBT1(next_info);
00595 SUSPEND_OBUF(18); *out_p++ = getBT2(next_info);
00596 SUSPEND_OBUF(19); *out_p++ = getBT3(next_info);
00597 continue;
00598 case GB4bt:
00599 SUSPEND_OBUF(29); *out_p++ = getGB4bt0(next_info);
00600 SUSPEND_OBUF(30); *out_p++ = getGB4bt1(next_info);
00601 SUSPEND_OBUF(31); *out_p++ = getGB4bt2(next_info);
00602 SUSPEND_OBUF(32); *out_p++ = getGB4bt3(next_info);
00603 continue;
00604 case STR1:
00605 tc->output_index = 0;
00606 while (tc->output_index < STR1_LENGTH(BYTE_ADDR(STR1_BYTEINDEX(next_info)))) {
00607 SUSPEND_OBUF(28); *out_p++ = BYTE_ADDR(STR1_BYTEINDEX(next_info))[1+tc->output_index];
00608 tc->output_index++;
00609 }
00610 continue;
00611 case FUNii:
00612 next_info = (VALUE)(*tr->func_ii)(TRANSCODING_STATE(tc), next_info);
00613 goto follow_info;
00614 case FUNsi:
00615 {
00616 const unsigned char *char_start;
00617 size_t char_len;
00618 char_start = transcode_char_start(tc, *in_pos, inchar_start, in_p, &char_len);
00619 next_info = (VALUE)(*tr->func_si)(TRANSCODING_STATE(tc), char_start, (size_t)char_len);
00620 goto follow_info;
00621 }
00622 case FUNio:
00623 SUSPEND_OBUF(13);
00624 if (tr->max_output <= out_stop - out_p)
00625 out_p += tr->func_io(TRANSCODING_STATE(tc),
00626 next_info, out_p, out_stop - out_p);
00627 else {
00628 writebuf_len = tr->func_io(TRANSCODING_STATE(tc),
00629 next_info,
00630 TRANSCODING_WRITEBUF(tc), TRANSCODING_WRITEBUF_SIZE(tc));
00631 writebuf_off = 0;
00632 while (writebuf_off < writebuf_len) {
00633 SUSPEND_OBUF(20);
00634 *out_p++ = TRANSCODING_WRITEBUF(tc)[writebuf_off++];
00635 }
00636 }
00637 break;
00638 case FUNso:
00639 {
00640 const unsigned char *char_start;
00641 size_t char_len;
00642 SUSPEND_OBUF(14);
00643 if (tr->max_output <= out_stop - out_p) {
00644 char_start = transcode_char_start(tc, *in_pos, inchar_start, in_p, &char_len);
00645 out_p += tr->func_so(TRANSCODING_STATE(tc),
00646 char_start, (size_t)char_len,
00647 out_p, out_stop - out_p);
00648 }
00649 else {
00650 char_start = transcode_char_start(tc, *in_pos, inchar_start, in_p, &char_len);
00651 writebuf_len = tr->func_so(TRANSCODING_STATE(tc),
00652 char_start, (size_t)char_len,
00653 TRANSCODING_WRITEBUF(tc), TRANSCODING_WRITEBUF_SIZE(tc));
00654 writebuf_off = 0;
00655 while (writebuf_off < writebuf_len) {
00656 SUSPEND_OBUF(22);
00657 *out_p++ = TRANSCODING_WRITEBUF(tc)[writebuf_off++];
00658 }
00659 }
00660 break;
00661 }
00662 case FUNsio:
00663 {
00664 const unsigned char *char_start;
00665 size_t char_len;
00666 SUSPEND_OBUF(33);
00667 if (tr->max_output <= out_stop - out_p) {
00668 char_start = transcode_char_start(tc, *in_pos, inchar_start, in_p, &char_len);
00669 out_p += tr->func_sio(TRANSCODING_STATE(tc),
00670 char_start, (size_t)char_len, next_info,
00671 out_p, out_stop - out_p);
00672 }
00673 else {
00674 char_start = transcode_char_start(tc, *in_pos, inchar_start, in_p, &char_len);
00675 writebuf_len = tr->func_sio(TRANSCODING_STATE(tc),
00676 char_start, (size_t)char_len, next_info,
00677 TRANSCODING_WRITEBUF(tc), TRANSCODING_WRITEBUF_SIZE(tc));
00678 writebuf_off = 0;
00679 while (writebuf_off < writebuf_len) {
00680 SUSPEND_OBUF(34);
00681 *out_p++ = TRANSCODING_WRITEBUF(tc)[writebuf_off++];
00682 }
00683 }
00684 break;
00685 }
00686 case INVALID:
00687 if (tc->recognized_len + (in_p - inchar_start) <= unitlen) {
00688 if (tc->recognized_len + (in_p - inchar_start) < unitlen)
00689 SUSPEND_AFTER_OUTPUT(26);
00690 while ((opt & ECONV_PARTIAL_INPUT) && tc->recognized_len + (in_stop - inchar_start) < unitlen) {
00691 in_p = in_stop;
00692 SUSPEND(econv_source_buffer_empty, 8);
00693 }
00694 if (tc->recognized_len + (in_stop - inchar_start) <= unitlen) {
00695 in_p = in_stop;
00696 }
00697 else {
00698 in_p = inchar_start + (unitlen - tc->recognized_len);
00699 }
00700 }
00701 else {
00702 ssize_t invalid_len;
00703 ssize_t discard_len;
00704 invalid_len = tc->recognized_len + (in_p - inchar_start);
00705 discard_len = ((invalid_len - 1) / unitlen) * unitlen;
00706 readagain_len = invalid_len - discard_len;
00707 }
00708 goto invalid;
00709 case UNDEF:
00710 goto undef;
00711 default:
00712 rb_raise(rb_eRuntimeError, "unknown transcoding instruction");
00713 }
00714 continue;
00715
00716 invalid:
00717 SUSPEND(econv_invalid_byte_sequence, 1);
00718 continue;
00719
00720 incomplete:
00721 SUSPEND(econv_incomplete_input, 27);
00722 continue;
00723
00724 undef:
00725 SUSPEND(econv_undefined_conversion, 2);
00726 continue;
00727 }
00728
00729
00730 if (tr->finish_func) {
00731 SUSPEND_OBUF(4);
00732 if (tr->max_output <= out_stop - out_p) {
00733 out_p += tr->finish_func(TRANSCODING_STATE(tc),
00734 out_p, out_stop - out_p);
00735 }
00736 else {
00737 writebuf_len = tr->finish_func(TRANSCODING_STATE(tc),
00738 TRANSCODING_WRITEBUF(tc), TRANSCODING_WRITEBUF_SIZE(tc));
00739 writebuf_off = 0;
00740 while (writebuf_off < writebuf_len) {
00741 SUSPEND_OBUF(23);
00742 *out_p++ = TRANSCODING_WRITEBUF(tc)[writebuf_off++];
00743 }
00744 }
00745 }
00746 while (1)
00747 SUSPEND(econv_finished, 6);
00748 #undef SUSPEND
00749 #undef next_table
00750 #undef next_info
00751 #undef next_byte
00752 #undef writebuf_len
00753 #undef writebuf_off
00754 }
00755
00756 static rb_econv_result_t
00757 transcode_restartable(const unsigned char **in_pos, unsigned char **out_pos,
00758 const unsigned char *in_stop, unsigned char *out_stop,
00759 rb_transcoding *tc,
00760 const int opt)
00761 {
00762 if (tc->readagain_len) {
00763 unsigned char *readagain_buf = ALLOCA_N(unsigned char, tc->readagain_len);
00764 const unsigned char *readagain_pos = readagain_buf;
00765 const unsigned char *readagain_stop = readagain_buf + tc->readagain_len;
00766 rb_econv_result_t res;
00767
00768 MEMCPY(readagain_buf, TRANSCODING_READBUF(tc) + tc->recognized_len,
00769 unsigned char, tc->readagain_len);
00770 tc->readagain_len = 0;
00771 res = transcode_restartable0(&readagain_pos, out_pos, readagain_stop, out_stop, tc, opt|ECONV_PARTIAL_INPUT);
00772 if (res != econv_source_buffer_empty) {
00773 MEMCPY(TRANSCODING_READBUF(tc) + tc->recognized_len + tc->readagain_len,
00774 readagain_pos, unsigned char, readagain_stop - readagain_pos);
00775 tc->readagain_len += readagain_stop - readagain_pos;
00776 return res;
00777 }
00778 }
00779 return transcode_restartable0(in_pos, out_pos, in_stop, out_stop, tc, opt);
00780 }
00781
00782 static rb_transcoding *
00783 rb_transcoding_open_by_transcoder(const rb_transcoder *tr, int flags)
00784 {
00785 rb_transcoding *tc;
00786
00787 tc = ALLOC(rb_transcoding);
00788 tc->transcoder = tr;
00789 tc->flags = flags;
00790 if (TRANSCODING_STATE_EMBED_MAX < tr->state_size)
00791 tc->state.ptr = xmalloc(tr->state_size);
00792 if (tr->state_init_func) {
00793 (tr->state_init_func)(TRANSCODING_STATE(tc));
00794 }
00795 tc->resume_position = 0;
00796 tc->recognized_len = 0;
00797 tc->readagain_len = 0;
00798 tc->writebuf_len = 0;
00799 tc->writebuf_off = 0;
00800 if ((int)sizeof(tc->readbuf.ary) < tr->max_input) {
00801 tc->readbuf.ptr = xmalloc(tr->max_input);
00802 }
00803 if ((int)sizeof(tc->writebuf.ary) < tr->max_output) {
00804 tc->writebuf.ptr = xmalloc(tr->max_output);
00805 }
00806 return tc;
00807 }
00808
00809 static rb_econv_result_t
00810 rb_transcoding_convert(rb_transcoding *tc,
00811 const unsigned char **input_ptr, const unsigned char *input_stop,
00812 unsigned char **output_ptr, unsigned char *output_stop,
00813 int flags)
00814 {
00815 return transcode_restartable(
00816 input_ptr, output_ptr,
00817 input_stop, output_stop,
00818 tc, flags);
00819 }
00820
00821 static void
00822 rb_transcoding_close(rb_transcoding *tc)
00823 {
00824 const rb_transcoder *tr = tc->transcoder;
00825 if (tr->state_fini_func) {
00826 (tr->state_fini_func)(TRANSCODING_STATE(tc));
00827 }
00828 if (TRANSCODING_STATE_EMBED_MAX < tr->state_size)
00829 xfree(tc->state.ptr);
00830 if ((int)sizeof(tc->readbuf.ary) < tr->max_input)
00831 xfree(tc->readbuf.ptr);
00832 if ((int)sizeof(tc->writebuf.ary) < tr->max_output)
00833 xfree(tc->writebuf.ptr);
00834 xfree(tc);
00835 }
00836
00837 static size_t
00838 rb_transcoding_memsize(rb_transcoding *tc)
00839 {
00840 size_t size = sizeof(rb_transcoding);
00841 const rb_transcoder *tr = tc->transcoder;
00842
00843 if (TRANSCODING_STATE_EMBED_MAX < tr->state_size) {
00844 size += tr->state_size;
00845 }
00846 if ((int)sizeof(tc->readbuf.ary) < tr->max_input) {
00847 size += tr->max_input;
00848 }
00849 if ((int)sizeof(tc->writebuf.ary) < tr->max_output) {
00850 size += tr->max_output;
00851 }
00852 return size;
00853 }
00854
00855 static rb_econv_t *
00856 rb_econv_alloc(int n_hint)
00857 {
00858 rb_econv_t *ec;
00859
00860 if (n_hint <= 0)
00861 n_hint = 1;
00862
00863 ec = ALLOC(rb_econv_t);
00864 ec->flags = 0;
00865 ec->source_encoding_name = NULL;
00866 ec->destination_encoding_name = NULL;
00867 ec->started = 0;
00868 ec->replacement_str = NULL;
00869 ec->replacement_len = 0;
00870 ec->replacement_enc = NULL;
00871 ec->replacement_allocated = 0;
00872 ec->in_buf_start = NULL;
00873 ec->in_data_start = NULL;
00874 ec->in_data_end = NULL;
00875 ec->in_buf_end = NULL;
00876 ec->num_allocated = n_hint;
00877 ec->num_trans = 0;
00878 ec->elems = ALLOC_N(rb_econv_elem_t, ec->num_allocated);
00879 ec->num_finished = 0;
00880 ec->last_tc = NULL;
00881 ec->last_error.result = econv_source_buffer_empty;
00882 ec->last_error.error_tc = NULL;
00883 ec->last_error.source_encoding = NULL;
00884 ec->last_error.destination_encoding = NULL;
00885 ec->last_error.error_bytes_start = NULL;
00886 ec->last_error.error_bytes_len = 0;
00887 ec->last_error.readagain_len = 0;
00888 ec->source_encoding = NULL;
00889 ec->destination_encoding = NULL;
00890 return ec;
00891 }
00892
00893 static int
00894 rb_econv_add_transcoder_at(rb_econv_t *ec, const rb_transcoder *tr, int i)
00895 {
00896 int n, j;
00897 int bufsize = 4096;
00898 unsigned char *p;
00899
00900 if (ec->num_trans == ec->num_allocated) {
00901 n = ec->num_allocated * 2;
00902 REALLOC_N(ec->elems, rb_econv_elem_t, n);
00903 ec->num_allocated = n;
00904 }
00905
00906 p = xmalloc(bufsize);
00907
00908 MEMMOVE(ec->elems+i+1, ec->elems+i, rb_econv_elem_t, ec->num_trans-i);
00909
00910 ec->elems[i].tc = rb_transcoding_open_by_transcoder(tr, 0);
00911 ec->elems[i].out_buf_start = p;
00912 ec->elems[i].out_buf_end = p + bufsize;
00913 ec->elems[i].out_data_start = p;
00914 ec->elems[i].out_data_end = p;
00915 ec->elems[i].last_result = econv_source_buffer_empty;
00916
00917 ec->num_trans++;
00918
00919 if (!DECORATOR_P(tr->src_encoding, tr->dst_encoding))
00920 for (j = ec->num_trans-1; i <= j; j--) {
00921 rb_transcoding *tc = ec->elems[j].tc;
00922 const rb_transcoder *tr2 = tc->transcoder;
00923 if (!DECORATOR_P(tr2->src_encoding, tr2->dst_encoding)) {
00924 ec->last_tc = tc;
00925 break;
00926 }
00927 }
00928
00929 return 0;
00930 }
00931
00932 static rb_econv_t *
00933 rb_econv_open_by_transcoder_entries(int n, transcoder_entry_t **entries)
00934 {
00935 rb_econv_t *ec;
00936 int i, ret;
00937
00938 for (i = 0; i < n; i++) {
00939 const rb_transcoder *tr;
00940 tr = load_transcoder_entry(entries[i]);
00941 if (!tr)
00942 return NULL;
00943 }
00944
00945 ec = rb_econv_alloc(n);
00946
00947 for (i = 0; i < n; i++) {
00948 const rb_transcoder *tr = load_transcoder_entry(entries[i]);
00949 ret = rb_econv_add_transcoder_at(ec, tr, ec->num_trans);
00950 if (ret == -1) {
00951 rb_econv_close(ec);
00952 return NULL;
00953 }
00954 }
00955
00956 return ec;
00957 }
00958
00959 struct trans_open_t {
00960 transcoder_entry_t **entries;
00961 int num_additional;
00962 };
00963
00964 static void
00965 trans_open_i(const char *sname, const char *dname, int depth, void *arg)
00966 {
00967 struct trans_open_t *toarg = arg;
00968
00969 if (!toarg->entries) {
00970 toarg->entries = ALLOC_N(transcoder_entry_t *, depth+1+toarg->num_additional);
00971 }
00972 toarg->entries[depth] = get_transcoder_entry(sname, dname);
00973 }
00974
00975 static rb_econv_t *
00976 rb_econv_open0(const char *sname, const char *dname, int ecflags)
00977 {
00978 transcoder_entry_t **entries = NULL;
00979 int num_trans;
00980 rb_econv_t *ec;
00981
00982 int sidx, didx;
00983
00984 if (*sname) {
00985 sidx = rb_enc_find_index(sname);
00986 if (0 <= sidx) {
00987 rb_enc_from_index(sidx);
00988 }
00989 }
00990
00991 if (*dname) {
00992 didx = rb_enc_find_index(dname);
00993 if (0 <= didx) {
00994 rb_enc_from_index(didx);
00995 }
00996 }
00997
00998 if (*sname == '\0' && *dname == '\0') {
00999 num_trans = 0;
01000 entries = NULL;
01001 }
01002 else {
01003 struct trans_open_t toarg;
01004 toarg.entries = NULL;
01005 toarg.num_additional = 0;
01006 num_trans = transcode_search_path(sname, dname, trans_open_i, (void *)&toarg);
01007 entries = toarg.entries;
01008 if (num_trans < 0) {
01009 xfree(entries);
01010 return NULL;
01011 }
01012 }
01013
01014 ec = rb_econv_open_by_transcoder_entries(num_trans, entries);
01015 xfree(entries);
01016 if (!ec)
01017 return NULL;
01018
01019 ec->flags = ecflags;
01020 ec->source_encoding_name = sname;
01021 ec->destination_encoding_name = dname;
01022
01023 return ec;
01024 }
01025
01026 #define MAX_ECFLAGS_DECORATORS 32
01027
01028 static int
01029 decorator_names(int ecflags, const char **decorators_ret)
01030 {
01031 int num_decorators;
01032
01033 switch (ecflags & ECONV_NEWLINE_DECORATOR_MASK) {
01034 case ECONV_UNIVERSAL_NEWLINE_DECORATOR:
01035 case ECONV_CRLF_NEWLINE_DECORATOR:
01036 case ECONV_CR_NEWLINE_DECORATOR:
01037 case 0:
01038 break;
01039 default:
01040 return -1;
01041 }
01042
01043 if ((ecflags & ECONV_XML_TEXT_DECORATOR) &&
01044 (ecflags & ECONV_XML_ATTR_CONTENT_DECORATOR))
01045 return -1;
01046
01047 num_decorators = 0;
01048
01049 if (ecflags & ECONV_XML_TEXT_DECORATOR)
01050 decorators_ret[num_decorators++] = "xml_text_escape";
01051 if (ecflags & ECONV_XML_ATTR_CONTENT_DECORATOR)
01052 decorators_ret[num_decorators++] = "xml_attr_content_escape";
01053 if (ecflags & ECONV_XML_ATTR_QUOTE_DECORATOR)
01054 decorators_ret[num_decorators++] = "xml_attr_quote";
01055
01056 if (ecflags & ECONV_CRLF_NEWLINE_DECORATOR)
01057 decorators_ret[num_decorators++] = "crlf_newline";
01058 if (ecflags & ECONV_CR_NEWLINE_DECORATOR)
01059 decorators_ret[num_decorators++] = "cr_newline";
01060 if (ecflags & ECONV_UNIVERSAL_NEWLINE_DECORATOR)
01061 decorators_ret[num_decorators++] = "universal_newline";
01062
01063 return num_decorators;
01064 }
01065
01066 rb_econv_t *
01067 rb_econv_open(const char *sname, const char *dname, int ecflags)
01068 {
01069 rb_econv_t *ec;
01070 int num_decorators;
01071 const char *decorators[MAX_ECFLAGS_DECORATORS];
01072 int i;
01073
01074 num_decorators = decorator_names(ecflags, decorators);
01075 if (num_decorators == -1)
01076 return NULL;
01077
01078 ec = rb_econv_open0(sname, dname, ecflags & ECONV_ERROR_HANDLER_MASK);
01079 if (!ec)
01080 return NULL;
01081
01082 for (i = 0; i < num_decorators; i++)
01083 if (rb_econv_decorate_at_last(ec, decorators[i]) == -1) {
01084 rb_econv_close(ec);
01085 return NULL;
01086 }
01087
01088 ec->flags |= ecflags & ~ECONV_ERROR_HANDLER_MASK;
01089
01090 return ec;
01091 }
01092
01093 static int
01094 trans_sweep(rb_econv_t *ec,
01095 const unsigned char **input_ptr, const unsigned char *input_stop,
01096 unsigned char **output_ptr, unsigned char *output_stop,
01097 int flags,
01098 int start)
01099 {
01100 int try;
01101 int i, f;
01102
01103 const unsigned char **ipp, *is, *iold;
01104 unsigned char **opp, *os, *oold;
01105 rb_econv_result_t res;
01106
01107 try = 1;
01108 while (try) {
01109 try = 0;
01110 for (i = start; i < ec->num_trans; i++) {
01111 rb_econv_elem_t *te = &ec->elems[i];
01112
01113 if (i == 0) {
01114 ipp = input_ptr;
01115 is = input_stop;
01116 }
01117 else {
01118 rb_econv_elem_t *prev_te = &ec->elems[i-1];
01119 ipp = (const unsigned char **)&prev_te->out_data_start;
01120 is = prev_te->out_data_end;
01121 }
01122
01123 if (i == ec->num_trans-1) {
01124 opp = output_ptr;
01125 os = output_stop;
01126 }
01127 else {
01128 if (te->out_buf_start != te->out_data_start) {
01129 ssize_t len = te->out_data_end - te->out_data_start;
01130 ssize_t off = te->out_data_start - te->out_buf_start;
01131 MEMMOVE(te->out_buf_start, te->out_data_start, unsigned char, len);
01132 te->out_data_start = te->out_buf_start;
01133 te->out_data_end -= off;
01134 }
01135 opp = &te->out_data_end;
01136 os = te->out_buf_end;
01137 }
01138
01139 f = flags;
01140 if (ec->num_finished != i)
01141 f |= ECONV_PARTIAL_INPUT;
01142 if (i == 0 && (flags & ECONV_AFTER_OUTPUT)) {
01143 start = 1;
01144 flags &= ~ECONV_AFTER_OUTPUT;
01145 }
01146 if (i != 0)
01147 f &= ~ECONV_AFTER_OUTPUT;
01148 iold = *ipp;
01149 oold = *opp;
01150 te->last_result = res = rb_transcoding_convert(te->tc, ipp, is, opp, os, f);
01151 if (iold != *ipp || oold != *opp)
01152 try = 1;
01153
01154 switch (res) {
01155 case econv_invalid_byte_sequence:
01156 case econv_incomplete_input:
01157 case econv_undefined_conversion:
01158 case econv_after_output:
01159 return i;
01160
01161 case econv_destination_buffer_full:
01162 case econv_source_buffer_empty:
01163 break;
01164
01165 case econv_finished:
01166 ec->num_finished = i+1;
01167 break;
01168 }
01169 }
01170 }
01171 return -1;
01172 }
01173
01174 static rb_econv_result_t
01175 rb_trans_conv(rb_econv_t *ec,
01176 const unsigned char **input_ptr, const unsigned char *input_stop,
01177 unsigned char **output_ptr, unsigned char *output_stop,
01178 int flags,
01179 int *result_position_ptr)
01180 {
01181 int i;
01182 int needreport_index;
01183 int sweep_start;
01184
01185 unsigned char empty_buf;
01186 unsigned char *empty_ptr = &empty_buf;
01187
01188 if (!input_ptr) {
01189 input_ptr = (const unsigned char **)&empty_ptr;
01190 input_stop = empty_ptr;
01191 }
01192
01193 if (!output_ptr) {
01194 output_ptr = &empty_ptr;
01195 output_stop = empty_ptr;
01196 }
01197
01198 if (ec->elems[0].last_result == econv_after_output)
01199 ec->elems[0].last_result = econv_source_buffer_empty;
01200
01201 needreport_index = -1;
01202 for (i = ec->num_trans-1; 0 <= i; i--) {
01203 switch (ec->elems[i].last_result) {
01204 case econv_invalid_byte_sequence:
01205 case econv_incomplete_input:
01206 case econv_undefined_conversion:
01207 case econv_after_output:
01208 case econv_finished:
01209 sweep_start = i+1;
01210 needreport_index = i;
01211 goto found_needreport;
01212
01213 case econv_destination_buffer_full:
01214 case econv_source_buffer_empty:
01215 break;
01216
01217 default:
01218 rb_bug("unexpected transcode last result");
01219 }
01220 }
01221
01222
01223
01224 if (ec->elems[ec->num_trans-1].last_result == econv_destination_buffer_full &&
01225 (flags & ECONV_AFTER_OUTPUT)) {
01226 rb_econv_result_t res;
01227
01228 res = rb_trans_conv(ec, NULL, NULL, output_ptr, output_stop,
01229 (flags & ~ECONV_AFTER_OUTPUT)|ECONV_PARTIAL_INPUT,
01230 result_position_ptr);
01231
01232 if (res == econv_source_buffer_empty)
01233 return econv_after_output;
01234 return res;
01235 }
01236
01237 sweep_start = 0;
01238
01239 found_needreport:
01240
01241 do {
01242 needreport_index = trans_sweep(ec, input_ptr, input_stop, output_ptr, output_stop, flags, sweep_start);
01243 sweep_start = needreport_index + 1;
01244 } while (needreport_index != -1 && needreport_index != ec->num_trans-1);
01245
01246 for (i = ec->num_trans-1; 0 <= i; i--) {
01247 if (ec->elems[i].last_result != econv_source_buffer_empty) {
01248 rb_econv_result_t res = ec->elems[i].last_result;
01249 if (res == econv_invalid_byte_sequence ||
01250 res == econv_incomplete_input ||
01251 res == econv_undefined_conversion ||
01252 res == econv_after_output) {
01253 ec->elems[i].last_result = econv_source_buffer_empty;
01254 }
01255 if (result_position_ptr)
01256 *result_position_ptr = i;
01257 return res;
01258 }
01259 }
01260 if (result_position_ptr)
01261 *result_position_ptr = -1;
01262 return econv_source_buffer_empty;
01263 }
01264
01265 static rb_econv_result_t
01266 rb_econv_convert0(rb_econv_t *ec,
01267 const unsigned char **input_ptr, const unsigned char *input_stop,
01268 unsigned char **output_ptr, unsigned char *output_stop,
01269 int flags)
01270 {
01271 rb_econv_result_t res;
01272 int result_position;
01273 int has_output = 0;
01274
01275 memset(&ec->last_error, 0, sizeof(ec->last_error));
01276
01277 if (ec->num_trans == 0) {
01278 size_t len;
01279 if (ec->in_buf_start && ec->in_data_start != ec->in_data_end) {
01280 if (output_stop - *output_ptr < ec->in_data_end - ec->in_data_start) {
01281 len = output_stop - *output_ptr;
01282 memcpy(*output_ptr, ec->in_data_start, len);
01283 *output_ptr = output_stop;
01284 ec->in_data_start += len;
01285 res = econv_destination_buffer_full;
01286 goto gotresult;
01287 }
01288 len = ec->in_data_end - ec->in_data_start;
01289 memcpy(*output_ptr, ec->in_data_start, len);
01290 *output_ptr += len;
01291 ec->in_data_start = ec->in_data_end = ec->in_buf_start;
01292 if (flags & ECONV_AFTER_OUTPUT) {
01293 res = econv_after_output;
01294 goto gotresult;
01295 }
01296 }
01297 if (output_stop - *output_ptr < input_stop - *input_ptr) {
01298 len = output_stop - *output_ptr;
01299 }
01300 else {
01301 len = input_stop - *input_ptr;
01302 }
01303 if (0 < len && (flags & ECONV_AFTER_OUTPUT)) {
01304 *(*output_ptr)++ = *(*input_ptr)++;
01305 res = econv_after_output;
01306 goto gotresult;
01307 }
01308 memcpy(*output_ptr, *input_ptr, len);
01309 *output_ptr += len;
01310 *input_ptr += len;
01311 if (*input_ptr != input_stop)
01312 res = econv_destination_buffer_full;
01313 else if (flags & ECONV_PARTIAL_INPUT)
01314 res = econv_source_buffer_empty;
01315 else
01316 res = econv_finished;
01317 goto gotresult;
01318 }
01319
01320 if (ec->elems[ec->num_trans-1].out_data_start) {
01321 unsigned char *data_start = ec->elems[ec->num_trans-1].out_data_start;
01322 unsigned char *data_end = ec->elems[ec->num_trans-1].out_data_end;
01323 if (data_start != data_end) {
01324 size_t len;
01325 if (output_stop - *output_ptr < data_end - data_start) {
01326 len = output_stop - *output_ptr;
01327 memcpy(*output_ptr, data_start, len);
01328 *output_ptr = output_stop;
01329 ec->elems[ec->num_trans-1].out_data_start += len;
01330 res = econv_destination_buffer_full;
01331 goto gotresult;
01332 }
01333 len = data_end - data_start;
01334 memcpy(*output_ptr, data_start, len);
01335 *output_ptr += len;
01336 ec->elems[ec->num_trans-1].out_data_start =
01337 ec->elems[ec->num_trans-1].out_data_end =
01338 ec->elems[ec->num_trans-1].out_buf_start;
01339 has_output = 1;
01340 }
01341 }
01342
01343 if (ec->in_buf_start &&
01344 ec->in_data_start != ec->in_data_end) {
01345 res = rb_trans_conv(ec, (const unsigned char **)&ec->in_data_start, ec->in_data_end, output_ptr, output_stop,
01346 (flags&~ECONV_AFTER_OUTPUT)|ECONV_PARTIAL_INPUT, &result_position);
01347 if (res != econv_source_buffer_empty)
01348 goto gotresult;
01349 }
01350
01351 if (has_output &&
01352 (flags & ECONV_AFTER_OUTPUT) &&
01353 *input_ptr != input_stop) {
01354 input_stop = *input_ptr;
01355 res = rb_trans_conv(ec, input_ptr, input_stop, output_ptr, output_stop, flags, &result_position);
01356 if (res == econv_source_buffer_empty)
01357 res = econv_after_output;
01358 }
01359 else if ((flags & ECONV_AFTER_OUTPUT) ||
01360 ec->num_trans == 1) {
01361 res = rb_trans_conv(ec, input_ptr, input_stop, output_ptr, output_stop, flags, &result_position);
01362 }
01363 else {
01364 flags |= ECONV_AFTER_OUTPUT;
01365 do {
01366 res = rb_trans_conv(ec, input_ptr, input_stop, output_ptr, output_stop, flags, &result_position);
01367 } while (res == econv_after_output);
01368 }
01369
01370 gotresult:
01371 ec->last_error.result = res;
01372 if (res == econv_invalid_byte_sequence ||
01373 res == econv_incomplete_input ||
01374 res == econv_undefined_conversion) {
01375 rb_transcoding *error_tc = ec->elems[result_position].tc;
01376 ec->last_error.error_tc = error_tc;
01377 ec->last_error.source_encoding = error_tc->transcoder->src_encoding;
01378 ec->last_error.destination_encoding = error_tc->transcoder->dst_encoding;
01379 ec->last_error.error_bytes_start = TRANSCODING_READBUF(error_tc);
01380 ec->last_error.error_bytes_len = error_tc->recognized_len;
01381 ec->last_error.readagain_len = error_tc->readagain_len;
01382 }
01383
01384 return res;
01385 }
01386
01387 static int output_replacement_character(rb_econv_t *ec);
01388
01389 static int
01390 output_hex_charref(rb_econv_t *ec)
01391 {
01392 int ret;
01393 unsigned char utfbuf[1024];
01394 const unsigned char *utf;
01395 size_t utf_len;
01396 int utf_allocated = 0;
01397 char charef_buf[16];
01398 const unsigned char *p;
01399
01400 if (encoding_equal(ec->last_error.source_encoding, "UTF-32BE")) {
01401 utf = ec->last_error.error_bytes_start;
01402 utf_len = ec->last_error.error_bytes_len;
01403 }
01404 else {
01405 utf = allocate_converted_string(ec->last_error.source_encoding, "UTF-32BE",
01406 ec->last_error.error_bytes_start, ec->last_error.error_bytes_len,
01407 utfbuf, sizeof(utfbuf),
01408 &utf_len);
01409 if (!utf)
01410 return -1;
01411 if (utf != utfbuf && utf != ec->last_error.error_bytes_start)
01412 utf_allocated = 1;
01413 }
01414
01415 if (utf_len % 4 != 0)
01416 goto fail;
01417
01418 p = utf;
01419 while (4 <= utf_len) {
01420 unsigned int u = 0;
01421 u += p[0] << 24;
01422 u += p[1] << 16;
01423 u += p[2] << 8;
01424 u += p[3];
01425 snprintf(charef_buf, sizeof(charef_buf), "&#x%X;", u);
01426
01427 ret = rb_econv_insert_output(ec, (unsigned char *)charef_buf, strlen(charef_buf), "US-ASCII");
01428 if (ret == -1)
01429 goto fail;
01430
01431 p += 4;
01432 utf_len -= 4;
01433 }
01434
01435 if (utf_allocated)
01436 xfree((void *)utf);
01437 return 0;
01438
01439 fail:
01440 if (utf_allocated)
01441 xfree((void *)utf);
01442 return -1;
01443 }
01444
01445 rb_econv_result_t
01446 rb_econv_convert(rb_econv_t *ec,
01447 const unsigned char **input_ptr, const unsigned char *input_stop,
01448 unsigned char **output_ptr, unsigned char *output_stop,
01449 int flags)
01450 {
01451 rb_econv_result_t ret;
01452
01453 unsigned char empty_buf;
01454 unsigned char *empty_ptr = &empty_buf;
01455
01456 ec->started = 1;
01457
01458 if (!input_ptr) {
01459 input_ptr = (const unsigned char **)&empty_ptr;
01460 input_stop = empty_ptr;
01461 }
01462
01463 if (!output_ptr) {
01464 output_ptr = &empty_ptr;
01465 output_stop = empty_ptr;
01466 }
01467
01468 resume:
01469 ret = rb_econv_convert0(ec, input_ptr, input_stop, output_ptr, output_stop, flags);
01470
01471 if (ret == econv_invalid_byte_sequence ||
01472 ret == econv_incomplete_input) {
01473
01474
01475 switch (ec->flags & ECONV_INVALID_MASK) {
01476 case ECONV_INVALID_REPLACE:
01477 if (output_replacement_character(ec) == 0)
01478 goto resume;
01479 }
01480 }
01481
01482 if (ret == econv_undefined_conversion) {
01483
01484
01485
01486 switch (ec->flags & ECONV_UNDEF_MASK) {
01487 case ECONV_UNDEF_REPLACE:
01488 if (output_replacement_character(ec) == 0)
01489 goto resume;
01490 break;
01491
01492 case ECONV_UNDEF_HEX_CHARREF:
01493 if (output_hex_charref(ec) == 0)
01494 goto resume;
01495 break;
01496 }
01497 }
01498
01499 return ret;
01500 }
01501
01502 const char *
01503 rb_econv_encoding_to_insert_output(rb_econv_t *ec)
01504 {
01505 rb_transcoding *tc = ec->last_tc;
01506 const rb_transcoder *tr;
01507
01508 if (tc == NULL)
01509 return "";
01510
01511 tr = tc->transcoder;
01512
01513 if (tr->asciicompat_type == asciicompat_encoder)
01514 return tr->src_encoding;
01515 return tr->dst_encoding;
01516 }
01517
01518 static unsigned char *
01519 allocate_converted_string(const char *sname, const char *dname,
01520 const unsigned char *str, size_t len,
01521 unsigned char *caller_dst_buf, size_t caller_dst_bufsize,
01522 size_t *dst_len_ptr)
01523 {
01524 unsigned char *dst_str;
01525 size_t dst_len;
01526 size_t dst_bufsize;
01527
01528 rb_econv_t *ec;
01529 rb_econv_result_t res;
01530
01531 const unsigned char *sp;
01532 unsigned char *dp;
01533
01534 if (caller_dst_buf)
01535 dst_bufsize = caller_dst_bufsize;
01536 else if (len == 0)
01537 dst_bufsize = 1;
01538 else
01539 dst_bufsize = len;
01540
01541 ec = rb_econv_open(sname, dname, 0);
01542 if (ec == NULL)
01543 return NULL;
01544 if (caller_dst_buf)
01545 dst_str = caller_dst_buf;
01546 else
01547 dst_str = xmalloc(dst_bufsize);
01548 dst_len = 0;
01549 sp = str;
01550 dp = dst_str+dst_len;
01551 res = rb_econv_convert(ec, &sp, str+len, &dp, dst_str+dst_bufsize, 0);
01552 dst_len = dp - dst_str;
01553 while (res == econv_destination_buffer_full) {
01554 if (SIZE_MAX/2 < dst_bufsize) {
01555 goto fail;
01556 }
01557 dst_bufsize *= 2;
01558 if (dst_str == caller_dst_buf) {
01559 unsigned char *tmp;
01560 tmp = xmalloc(dst_bufsize);
01561 memcpy(tmp, dst_str, dst_bufsize/2);
01562 dst_str = tmp;
01563 }
01564 else {
01565 dst_str = xrealloc(dst_str, dst_bufsize);
01566 }
01567 dp = dst_str+dst_len;
01568 res = rb_econv_convert(ec, &sp, str+len, &dp, dst_str+dst_bufsize, 0);
01569 dst_len = dp - dst_str;
01570 }
01571 if (res != econv_finished) {
01572 goto fail;
01573 }
01574 rb_econv_close(ec);
01575 *dst_len_ptr = dst_len;
01576 return dst_str;
01577
01578 fail:
01579 if (dst_str != caller_dst_buf)
01580 xfree(dst_str);
01581 rb_econv_close(ec);
01582 return NULL;
01583 }
01584
01585
01586 int
01587 rb_econv_insert_output(rb_econv_t *ec,
01588 const unsigned char *str, size_t len, const char *str_encoding)
01589 {
01590 const char *insert_encoding = rb_econv_encoding_to_insert_output(ec);
01591 unsigned char insert_buf[4096];
01592 const unsigned char *insert_str = NULL;
01593 size_t insert_len;
01594
01595 int last_trans_index;
01596 rb_transcoding *tc;
01597
01598 unsigned char **buf_start_p;
01599 unsigned char **data_start_p;
01600 unsigned char **data_end_p;
01601 unsigned char **buf_end_p;
01602
01603 size_t need;
01604
01605 ec->started = 1;
01606
01607 if (len == 0)
01608 return 0;
01609
01610 if (encoding_equal(insert_encoding, str_encoding)) {
01611 insert_str = str;
01612 insert_len = len;
01613 }
01614 else {
01615 insert_str = allocate_converted_string(str_encoding, insert_encoding,
01616 str, len, insert_buf, sizeof(insert_buf), &insert_len);
01617 if (insert_str == NULL)
01618 return -1;
01619 }
01620
01621 need = insert_len;
01622
01623 last_trans_index = ec->num_trans-1;
01624 if (ec->num_trans == 0) {
01625 tc = NULL;
01626 buf_start_p = &ec->in_buf_start;
01627 data_start_p = &ec->in_data_start;
01628 data_end_p = &ec->in_data_end;
01629 buf_end_p = &ec->in_buf_end;
01630 }
01631 else if (ec->elems[last_trans_index].tc->transcoder->asciicompat_type == asciicompat_encoder) {
01632 tc = ec->elems[last_trans_index].tc;
01633 need += tc->readagain_len;
01634 if (need < insert_len)
01635 goto fail;
01636 if (last_trans_index == 0) {
01637 buf_start_p = &ec->in_buf_start;
01638 data_start_p = &ec->in_data_start;
01639 data_end_p = &ec->in_data_end;
01640 buf_end_p = &ec->in_buf_end;
01641 }
01642 else {
01643 rb_econv_elem_t *ee = &ec->elems[last_trans_index-1];
01644 buf_start_p = &ee->out_buf_start;
01645 data_start_p = &ee->out_data_start;
01646 data_end_p = &ee->out_data_end;
01647 buf_end_p = &ee->out_buf_end;
01648 }
01649 }
01650 else {
01651 rb_econv_elem_t *ee = &ec->elems[last_trans_index];
01652 buf_start_p = &ee->out_buf_start;
01653 data_start_p = &ee->out_data_start;
01654 data_end_p = &ee->out_data_end;
01655 buf_end_p = &ee->out_buf_end;
01656 tc = ec->elems[last_trans_index].tc;
01657 }
01658
01659 if (*buf_start_p == NULL) {
01660 unsigned char *buf = xmalloc(need);
01661 *buf_start_p = buf;
01662 *data_start_p = buf;
01663 *data_end_p = buf;
01664 *buf_end_p = buf+need;
01665 }
01666 else if ((size_t)(*buf_end_p - *data_end_p) < need) {
01667 MEMMOVE(*buf_start_p, *data_start_p, unsigned char, *data_end_p - *data_start_p);
01668 *data_end_p = *buf_start_p + (*data_end_p - *data_start_p);
01669 *data_start_p = *buf_start_p;
01670 if ((size_t)(*buf_end_p - *data_end_p) < need) {
01671 unsigned char *buf;
01672 size_t s = (*data_end_p - *buf_start_p) + need;
01673 if (s < need)
01674 goto fail;
01675 buf = xrealloc(*buf_start_p, s);
01676 *data_start_p = buf;
01677 *data_end_p = buf + (*data_end_p - *buf_start_p);
01678 *buf_start_p = buf;
01679 *buf_end_p = buf + s;
01680 }
01681 }
01682
01683 memcpy(*data_end_p, insert_str, insert_len);
01684 *data_end_p += insert_len;
01685 if (tc && tc->transcoder->asciicompat_type == asciicompat_encoder) {
01686 memcpy(*data_end_p, TRANSCODING_READBUF(tc)+tc->recognized_len, tc->readagain_len);
01687 *data_end_p += tc->readagain_len;
01688 tc->readagain_len = 0;
01689 }
01690
01691 if (insert_str != str && insert_str != insert_buf)
01692 xfree((void*)insert_str);
01693 return 0;
01694
01695 fail:
01696 if (insert_str != str && insert_str != insert_buf)
01697 xfree((void*)insert_str);
01698 return -1;
01699 }
01700
01701 void
01702 rb_econv_close(rb_econv_t *ec)
01703 {
01704 int i;
01705
01706 if (ec->replacement_allocated) {
01707 xfree((void *)ec->replacement_str);
01708 }
01709 for (i = 0; i < ec->num_trans; i++) {
01710 rb_transcoding_close(ec->elems[i].tc);
01711 if (ec->elems[i].out_buf_start)
01712 xfree(ec->elems[i].out_buf_start);
01713 }
01714 xfree(ec->in_buf_start);
01715 xfree(ec->elems);
01716 xfree(ec);
01717 }
01718
01719 size_t
01720 rb_econv_memsize(rb_econv_t *ec)
01721 {
01722 size_t size = sizeof(rb_econv_t);
01723 int i;
01724
01725 if (ec->replacement_allocated) {
01726 size += ec->replacement_len;
01727 }
01728 for (i = 0; i < ec->num_trans; i++) {
01729 size += rb_transcoding_memsize(ec->elems[i].tc);
01730
01731 if (ec->elems[i].out_buf_start) {
01732 size += ec->elems[i].out_buf_end - ec->elems[i].out_buf_start;
01733 }
01734 }
01735 size += ec->in_buf_end - ec->in_buf_start;
01736 size += sizeof(rb_econv_elem_t) * ec->num_allocated;
01737
01738 return size;
01739 }
01740
01741 int
01742 rb_econv_putbackable(rb_econv_t *ec)
01743 {
01744 if (ec->num_trans == 0)
01745 return 0;
01746 #if SIZEOF_SIZE_T > SIZEOF_INT
01747 if (ec->elems[0].tc->readagain_len > INT_MAX) return INT_MAX;
01748 #endif
01749 return (int)ec->elems[0].tc->readagain_len;
01750 }
01751
01752 void
01753 rb_econv_putback(rb_econv_t *ec, unsigned char *p, int n)
01754 {
01755 rb_transcoding *tc;
01756 if (ec->num_trans == 0 || n == 0)
01757 return;
01758 tc = ec->elems[0].tc;
01759 memcpy(p, TRANSCODING_READBUF(tc) + tc->recognized_len + tc->readagain_len - n, n);
01760 tc->readagain_len -= n;
01761 }
01762
01763 struct asciicompat_encoding_t {
01764 const char *ascii_compat_name;
01765 const char *ascii_incompat_name;
01766 };
01767
01768 static int
01769 asciicompat_encoding_i(st_data_t key, st_data_t val, st_data_t arg)
01770 {
01771 struct asciicompat_encoding_t *data = (struct asciicompat_encoding_t *)arg;
01772 transcoder_entry_t *entry = (transcoder_entry_t *)val;
01773 const rb_transcoder *tr;
01774
01775 if (DECORATOR_P(entry->sname, entry->dname))
01776 return ST_CONTINUE;
01777 tr = load_transcoder_entry(entry);
01778 if (tr && tr->asciicompat_type == asciicompat_decoder) {
01779 data->ascii_compat_name = tr->dst_encoding;
01780 return ST_STOP;
01781 }
01782 return ST_CONTINUE;
01783 }
01784
01785 const char *
01786 rb_econv_asciicompat_encoding(const char *ascii_incompat_name)
01787 {
01788 st_data_t v;
01789 st_table *table2;
01790 struct asciicompat_encoding_t data;
01791
01792 if (!st_lookup(transcoder_table, (st_data_t)ascii_incompat_name, &v))
01793 return NULL;
01794 table2 = (st_table *)v;
01795
01796
01797
01798
01799
01800
01801
01802
01803 if (table2->num_entries != 1)
01804 return NULL;
01805
01806 data.ascii_incompat_name = ascii_incompat_name;
01807 data.ascii_compat_name = NULL;
01808 st_foreach(table2, asciicompat_encoding_i, (st_data_t)&data);
01809 return data.ascii_compat_name;
01810 }
01811
01812 VALUE
01813 rb_econv_append(rb_econv_t *ec, const char *ss, long len, VALUE dst, int flags)
01814 {
01815 unsigned const char *sp, *se;
01816 unsigned char *ds, *dp, *de;
01817 rb_econv_result_t res;
01818 int max_output;
01819
01820 if (NIL_P(dst)) {
01821 dst = rb_str_buf_new(len);
01822 if (ec->destination_encoding)
01823 rb_enc_associate(dst, ec->destination_encoding);
01824 }
01825
01826 if (ec->last_tc)
01827 max_output = ec->last_tc->transcoder->max_output;
01828 else
01829 max_output = 1;
01830
01831 do {
01832 long dlen = RSTRING_LEN(dst);
01833 if (rb_str_capacity(dst) - dlen < (size_t)len + max_output) {
01834 unsigned long new_capa = (unsigned long)dlen + len + max_output;
01835 if (LONG_MAX < new_capa)
01836 rb_raise(rb_eArgError, "too long string");
01837 rb_str_resize(dst, new_capa);
01838 rb_str_set_len(dst, dlen);
01839 }
01840 sp = (const unsigned char *)ss;
01841 se = sp + len;
01842 ds = (unsigned char *)RSTRING_PTR(dst);
01843 de = ds + rb_str_capacity(dst);
01844 dp = ds += dlen;
01845 res = rb_econv_convert(ec, &sp, se, &dp, de, flags);
01846 len -= (const char *)sp - ss;
01847 ss = (const char *)sp;
01848 rb_str_set_len(dst, dlen + (dp - ds));
01849 rb_econv_check_error(ec);
01850 } while (res == econv_destination_buffer_full);
01851
01852 return dst;
01853 }
01854
01855 VALUE
01856 rb_econv_substr_append(rb_econv_t *ec, VALUE src, long off, long len, VALUE dst, int flags)
01857 {
01858 src = rb_str_new_frozen(src);
01859 dst = rb_econv_append(ec, RSTRING_PTR(src) + off, len, dst, flags);
01860 RB_GC_GUARD(src);
01861 return dst;
01862 }
01863
01864 VALUE
01865 rb_econv_str_append(rb_econv_t *ec, VALUE src, VALUE dst, int flags)
01866 {
01867 return rb_econv_substr_append(ec, src, 0, RSTRING_LEN(src), dst, flags);
01868 }
01869
01870 VALUE
01871 rb_econv_substr_convert(rb_econv_t *ec, VALUE src, long byteoff, long bytesize, int flags)
01872 {
01873 return rb_econv_substr_append(ec, src, byteoff, bytesize, Qnil, flags);
01874 }
01875
01876 VALUE
01877 rb_econv_str_convert(rb_econv_t *ec, VALUE src, int flags)
01878 {
01879 return rb_econv_substr_append(ec, src, 0, RSTRING_LEN(src), Qnil, flags);
01880 }
01881
01882 static int
01883 rb_econv_add_converter(rb_econv_t *ec, const char *sname, const char *dname, int n)
01884 {
01885 transcoder_entry_t *entry;
01886 const rb_transcoder *tr;
01887
01888 if (ec->started != 0)
01889 return -1;
01890
01891 entry = get_transcoder_entry(sname, dname);
01892 if (!entry)
01893 return -1;
01894
01895 tr = load_transcoder_entry(entry);
01896 if (!tr) return -1;
01897
01898 return rb_econv_add_transcoder_at(ec, tr, n);
01899 }
01900
01901 static int
01902 rb_econv_decorate_at(rb_econv_t *ec, const char *decorator_name, int n)
01903 {
01904 return rb_econv_add_converter(ec, "", decorator_name, n);
01905 }
01906
01907 int
01908 rb_econv_decorate_at_first(rb_econv_t *ec, const char *decorator_name)
01909 {
01910 const rb_transcoder *tr;
01911
01912 if (ec->num_trans == 0)
01913 return rb_econv_decorate_at(ec, decorator_name, 0);
01914
01915 tr = ec->elems[0].tc->transcoder;
01916
01917 if (!DECORATOR_P(tr->src_encoding, tr->dst_encoding) &&
01918 tr->asciicompat_type == asciicompat_decoder)
01919 return rb_econv_decorate_at(ec, decorator_name, 1);
01920
01921 return rb_econv_decorate_at(ec, decorator_name, 0);
01922 }
01923
01924 int
01925 rb_econv_decorate_at_last(rb_econv_t *ec, const char *decorator_name)
01926 {
01927 const rb_transcoder *tr;
01928
01929 if (ec->num_trans == 0)
01930 return rb_econv_decorate_at(ec, decorator_name, 0);
01931
01932 tr = ec->elems[ec->num_trans-1].tc->transcoder;
01933
01934 if (!DECORATOR_P(tr->src_encoding, tr->dst_encoding) &&
01935 tr->asciicompat_type == asciicompat_encoder)
01936 return rb_econv_decorate_at(ec, decorator_name, ec->num_trans-1);
01937
01938 return rb_econv_decorate_at(ec, decorator_name, ec->num_trans);
01939 }
01940
01941 void
01942 rb_econv_binmode(rb_econv_t *ec)
01943 {
01944 const char *dname = 0;
01945
01946 switch (ec->flags & ECONV_NEWLINE_DECORATOR_MASK) {
01947 case ECONV_UNIVERSAL_NEWLINE_DECORATOR:
01948 dname = "universal_newline";
01949 break;
01950 case ECONV_CRLF_NEWLINE_DECORATOR:
01951 dname = "crlf_newline";
01952 break;
01953 case ECONV_CR_NEWLINE_DECORATOR:
01954 dname = "cr_newline";
01955 break;
01956 }
01957
01958 if (dname) {
01959 const rb_transcoder *transcoder = get_transcoder_entry("", dname)->transcoder;
01960 int num_trans = ec->num_trans;
01961 int i, j = 0;
01962
01963 for (i=0; i < num_trans; i++) {
01964 if (transcoder == ec->elems[i].tc->transcoder) {
01965 rb_transcoding_close(ec->elems[i].tc);
01966 xfree(ec->elems[i].out_buf_start);
01967 ec->num_trans--;
01968 }
01969 else
01970 ec->elems[j++] = ec->elems[i];
01971 }
01972 }
01973
01974 ec->flags &= ~ECONV_NEWLINE_DECORATOR_MASK;
01975 }
01976
01977 static VALUE
01978 econv_description(const char *sname, const char *dname, int ecflags, VALUE mesg)
01979 {
01980 int has_description = 0;
01981
01982 if (NIL_P(mesg))
01983 mesg = rb_str_new(NULL, 0);
01984
01985 if (*sname != '\0' || *dname != '\0') {
01986 if (*sname == '\0')
01987 rb_str_cat2(mesg, dname);
01988 else if (*dname == '\0')
01989 rb_str_cat2(mesg, sname);
01990 else
01991 rb_str_catf(mesg, "%s to %s", sname, dname);
01992 has_description = 1;
01993 }
01994
01995 if (ecflags & (ECONV_NEWLINE_DECORATOR_MASK|
01996 ECONV_XML_TEXT_DECORATOR|
01997 ECONV_XML_ATTR_CONTENT_DECORATOR|
01998 ECONV_XML_ATTR_QUOTE_DECORATOR)) {
01999 const char *pre = "";
02000 if (has_description)
02001 rb_str_cat2(mesg, " with ");
02002 if (ecflags & ECONV_UNIVERSAL_NEWLINE_DECORATOR) {
02003 rb_str_cat2(mesg, pre); pre = ",";
02004 rb_str_cat2(mesg, "universal_newline");
02005 }
02006 if (ecflags & ECONV_CRLF_NEWLINE_DECORATOR) {
02007 rb_str_cat2(mesg, pre); pre = ",";
02008 rb_str_cat2(mesg, "crlf_newline");
02009 }
02010 if (ecflags & ECONV_CR_NEWLINE_DECORATOR) {
02011 rb_str_cat2(mesg, pre); pre = ",";
02012 rb_str_cat2(mesg, "cr_newline");
02013 }
02014 if (ecflags & ECONV_XML_TEXT_DECORATOR) {
02015 rb_str_cat2(mesg, pre); pre = ",";
02016 rb_str_cat2(mesg, "xml_text");
02017 }
02018 if (ecflags & ECONV_XML_ATTR_CONTENT_DECORATOR) {
02019 rb_str_cat2(mesg, pre); pre = ",";
02020 rb_str_cat2(mesg, "xml_attr_content");
02021 }
02022 if (ecflags & ECONV_XML_ATTR_QUOTE_DECORATOR) {
02023 rb_str_cat2(mesg, pre); pre = ",";
02024 rb_str_cat2(mesg, "xml_attr_quote");
02025 }
02026 has_description = 1;
02027 }
02028 if (!has_description) {
02029 rb_str_cat2(mesg, "no-conversion");
02030 }
02031
02032 return mesg;
02033 }
02034
02035 VALUE
02036 rb_econv_open_exc(const char *sname, const char *dname, int ecflags)
02037 {
02038 VALUE mesg, exc;
02039 mesg = rb_str_new_cstr("code converter not found (");
02040 econv_description(sname, dname, ecflags, mesg);
02041 rb_str_cat2(mesg, ")");
02042 exc = rb_exc_new3(rb_eConverterNotFoundError, mesg);
02043 return exc;
02044 }
02045
02046 static VALUE
02047 make_econv_exception(rb_econv_t *ec)
02048 {
02049 VALUE mesg, exc;
02050 if (ec->last_error.result == econv_invalid_byte_sequence ||
02051 ec->last_error.result == econv_incomplete_input) {
02052 const char *err = (const char *)ec->last_error.error_bytes_start;
02053 size_t error_len = ec->last_error.error_bytes_len;
02054 VALUE bytes = rb_str_new(err, error_len);
02055 VALUE dumped = rb_str_dump(bytes);
02056 size_t readagain_len = ec->last_error.readagain_len;
02057 VALUE bytes2 = Qnil;
02058 VALUE dumped2;
02059 int idx;
02060 if (ec->last_error.result == econv_incomplete_input) {
02061 mesg = rb_sprintf("incomplete %s on %s",
02062 StringValueCStr(dumped),
02063 ec->last_error.source_encoding);
02064 }
02065 else if (readagain_len) {
02066 bytes2 = rb_str_new(err+error_len, readagain_len);
02067 dumped2 = rb_str_dump(bytes2);
02068 mesg = rb_sprintf("%s followed by %s on %s",
02069 StringValueCStr(dumped),
02070 StringValueCStr(dumped2),
02071 ec->last_error.source_encoding);
02072 }
02073 else {
02074 mesg = rb_sprintf("%s on %s",
02075 StringValueCStr(dumped),
02076 ec->last_error.source_encoding);
02077 }
02078
02079 exc = rb_exc_new3(rb_eInvalidByteSequenceError, mesg);
02080 rb_ivar_set(exc, rb_intern("error_bytes"), bytes);
02081 rb_ivar_set(exc, rb_intern("readagain_bytes"), bytes2);
02082 rb_ivar_set(exc, rb_intern("incomplete_input"), ec->last_error.result == econv_incomplete_input ? Qtrue : Qfalse);
02083
02084 set_encs:
02085 rb_ivar_set(exc, rb_intern("source_encoding_name"), rb_str_new2(ec->last_error.source_encoding));
02086 rb_ivar_set(exc, rb_intern("destination_encoding_name"), rb_str_new2(ec->last_error.destination_encoding));
02087 idx = rb_enc_find_index(ec->last_error.source_encoding);
02088 if (0 <= idx)
02089 rb_ivar_set(exc, rb_intern("source_encoding"), rb_enc_from_encoding(rb_enc_from_index(idx)));
02090 idx = rb_enc_find_index(ec->last_error.destination_encoding);
02091 if (0 <= idx)
02092 rb_ivar_set(exc, rb_intern("destination_encoding"), rb_enc_from_encoding(rb_enc_from_index(idx)));
02093 return exc;
02094 }
02095 if (ec->last_error.result == econv_undefined_conversion) {
02096 VALUE bytes = rb_str_new((const char *)ec->last_error.error_bytes_start,
02097 ec->last_error.error_bytes_len);
02098 VALUE dumped = Qnil;
02099 int idx;
02100 if (strcmp(ec->last_error.source_encoding, "UTF-8") == 0) {
02101 rb_encoding *utf8 = rb_utf8_encoding();
02102 const char *start, *end;
02103 int n;
02104 start = (const char *)ec->last_error.error_bytes_start;
02105 end = start + ec->last_error.error_bytes_len;
02106 n = rb_enc_precise_mbclen(start, end, utf8);
02107 if (MBCLEN_CHARFOUND_P(n) &&
02108 (size_t)MBCLEN_CHARFOUND_LEN(n) == ec->last_error.error_bytes_len) {
02109 unsigned int cc = rb_enc_mbc_to_codepoint(start, end, utf8);
02110 dumped = rb_sprintf("U+%04X", cc);
02111 }
02112 }
02113 if (dumped == Qnil)
02114 dumped = rb_str_dump(bytes);
02115 if (strcmp(ec->last_error.source_encoding,
02116 ec->source_encoding_name) == 0 &&
02117 strcmp(ec->last_error.destination_encoding,
02118 ec->destination_encoding_name) == 0) {
02119 mesg = rb_sprintf("%s from %s to %s",
02120 StringValueCStr(dumped),
02121 ec->last_error.source_encoding,
02122 ec->last_error.destination_encoding);
02123 }
02124 else {
02125 int i;
02126 mesg = rb_sprintf("%s to %s in conversion from %s",
02127 StringValueCStr(dumped),
02128 ec->last_error.destination_encoding,
02129 ec->source_encoding_name);
02130 for (i = 0; i < ec->num_trans; i++) {
02131 const rb_transcoder *tr = ec->elems[i].tc->transcoder;
02132 if (!DECORATOR_P(tr->src_encoding, tr->dst_encoding))
02133 rb_str_catf(mesg, " to %s",
02134 ec->elems[i].tc->transcoder->dst_encoding);
02135 }
02136 }
02137 exc = rb_exc_new3(rb_eUndefinedConversionError, mesg);
02138 idx = rb_enc_find_index(ec->last_error.source_encoding);
02139 if (0 <= idx)
02140 rb_enc_associate_index(bytes, idx);
02141 rb_ivar_set(exc, rb_intern("error_char"), bytes);
02142 goto set_encs;
02143 }
02144 return Qnil;
02145 }
02146
02147 static void
02148 more_output_buffer(
02149 VALUE destination,
02150 unsigned char *(*resize_destination)(VALUE, size_t, size_t),
02151 int max_output,
02152 unsigned char **out_start_ptr,
02153 unsigned char **out_pos,
02154 unsigned char **out_stop_ptr)
02155 {
02156 size_t len = (*out_pos - *out_start_ptr);
02157 size_t new_len = (len + max_output) * 2;
02158 *out_start_ptr = resize_destination(destination, len, new_len);
02159 *out_pos = *out_start_ptr + len;
02160 *out_stop_ptr = *out_start_ptr + new_len;
02161 }
02162
02163 static int
02164 make_replacement(rb_econv_t *ec)
02165 {
02166 rb_transcoding *tc;
02167 const rb_transcoder *tr;
02168 const unsigned char *replacement;
02169 const char *repl_enc;
02170 const char *ins_enc;
02171 size_t len;
02172
02173 if (ec->replacement_str)
02174 return 0;
02175
02176 ins_enc = rb_econv_encoding_to_insert_output(ec);
02177
02178 tc = ec->last_tc;
02179 if (*ins_enc) {
02180 tr = tc->transcoder;
02181 rb_enc_find(tr->dst_encoding);
02182 replacement = (const unsigned char *)get_replacement_character(ins_enc, &len, &repl_enc);
02183 }
02184 else {
02185 replacement = (unsigned char *)"?";
02186 len = 1;
02187 repl_enc = "";
02188 }
02189
02190 ec->replacement_str = replacement;
02191 ec->replacement_len = len;
02192 ec->replacement_enc = repl_enc;
02193 ec->replacement_allocated = 0;
02194 return 0;
02195 }
02196
02197 int
02198 rb_econv_set_replacement(rb_econv_t *ec,
02199 const unsigned char *str, size_t len, const char *encname)
02200 {
02201 unsigned char *str2;
02202 size_t len2;
02203 const char *encname2;
02204
02205 encname2 = rb_econv_encoding_to_insert_output(ec);
02206
02207 if (encoding_equal(encname, encname2)) {
02208 str2 = xmalloc(len);
02209 MEMCPY(str2, str, unsigned char, len);
02210 len2 = len;
02211 encname2 = encname;
02212 }
02213 else {
02214 str2 = allocate_converted_string(encname, encname2, str, len, NULL, 0, &len2);
02215 if (!str2)
02216 return -1;
02217 }
02218
02219 if (ec->replacement_allocated) {
02220 xfree((void *)ec->replacement_str);
02221 }
02222 ec->replacement_allocated = 1;
02223 ec->replacement_str = str2;
02224 ec->replacement_len = len2;
02225 ec->replacement_enc = encname2;
02226 return 0;
02227 }
02228
02229 static int
02230 output_replacement_character(rb_econv_t *ec)
02231 {
02232 int ret;
02233
02234 if (make_replacement(ec) == -1)
02235 return -1;
02236
02237 ret = rb_econv_insert_output(ec, ec->replacement_str, ec->replacement_len, ec->replacement_enc);
02238 if (ret == -1)
02239 return -1;
02240
02241 return 0;
02242 }
02243
02244 #if 1
02245 #define hash_fallback rb_hash_aref
02246
02247 static VALUE
02248 proc_fallback(VALUE fallback, VALUE c)
02249 {
02250 return rb_proc_call(fallback, rb_ary_new4(1, &c));
02251 }
02252
02253 static VALUE
02254 method_fallback(VALUE fallback, VALUE c)
02255 {
02256 return rb_method_call(1, &c, fallback);
02257 }
02258
02259 static VALUE
02260 aref_fallback(VALUE fallback, VALUE c)
02261 {
02262 return rb_funcall3(fallback, sym_aref, 1, &c);
02263 }
02264
02265 static void
02266 transcode_loop(const unsigned char **in_pos, unsigned char **out_pos,
02267 const unsigned char *in_stop, unsigned char *out_stop,
02268 VALUE destination,
02269 unsigned char *(*resize_destination)(VALUE, size_t, size_t),
02270 const char *src_encoding,
02271 const char *dst_encoding,
02272 int ecflags,
02273 VALUE ecopts)
02274 {
02275 rb_econv_t *ec;
02276 rb_transcoding *last_tc;
02277 rb_econv_result_t ret;
02278 unsigned char *out_start = *out_pos;
02279 int max_output;
02280 VALUE exc;
02281 VALUE fallback = Qnil;
02282 VALUE (*fallback_func)(VALUE, VALUE) = 0;
02283
02284 ec = rb_econv_open_opts(src_encoding, dst_encoding, ecflags, ecopts);
02285 if (!ec)
02286 rb_exc_raise(rb_econv_open_exc(src_encoding, dst_encoding, ecflags));
02287
02288 if (!NIL_P(ecopts) && RB_TYPE_P(ecopts, T_HASH)) {
02289 fallback = rb_hash_aref(ecopts, sym_fallback);
02290 if (RB_TYPE_P(fallback, T_HASH)) {
02291 fallback_func = hash_fallback;
02292 }
02293 else if (rb_obj_is_proc(fallback)) {
02294 fallback_func = proc_fallback;
02295 }
02296 else if (rb_obj_is_method(fallback)) {
02297 fallback_func = method_fallback;
02298 }
02299 else {
02300 fallback_func = aref_fallback;
02301 }
02302 }
02303 last_tc = ec->last_tc;
02304 max_output = last_tc ? last_tc->transcoder->max_output : 1;
02305
02306 resume:
02307 ret = rb_econv_convert(ec, in_pos, in_stop, out_pos, out_stop, 0);
02308
02309 if (!NIL_P(fallback) && ret == econv_undefined_conversion) {
02310 VALUE rep = rb_enc_str_new(
02311 (const char *)ec->last_error.error_bytes_start,
02312 ec->last_error.error_bytes_len,
02313 rb_enc_find(ec->last_error.source_encoding));
02314 rep = (*fallback_func)(fallback, rep);
02315 if (rep != Qundef && !NIL_P(rep)) {
02316 StringValue(rep);
02317 ret = rb_econv_insert_output(ec, (const unsigned char *)RSTRING_PTR(rep),
02318 RSTRING_LEN(rep), rb_enc_name(rb_enc_get(rep)));
02319 if ((int)ret == -1) {
02320 rb_raise(rb_eArgError, "too big fallback string");
02321 }
02322 goto resume;
02323 }
02324 }
02325
02326 if (ret == econv_invalid_byte_sequence ||
02327 ret == econv_incomplete_input ||
02328 ret == econv_undefined_conversion) {
02329 exc = make_econv_exception(ec);
02330 rb_econv_close(ec);
02331 rb_exc_raise(exc);
02332 }
02333
02334 if (ret == econv_destination_buffer_full) {
02335 more_output_buffer(destination, resize_destination, max_output, &out_start, out_pos, &out_stop);
02336 goto resume;
02337 }
02338
02339 rb_econv_close(ec);
02340 return;
02341 }
02342 #else
02343
02344 static void
02345 transcode_loop(const unsigned char **in_pos, unsigned char **out_pos,
02346 const unsigned char *in_stop, unsigned char *out_stop,
02347 VALUE destination,
02348 unsigned char *(*resize_destination)(VALUE, size_t, size_t),
02349 const char *src_encoding,
02350 const char *dst_encoding,
02351 int ecflags,
02352 VALUE ecopts)
02353 {
02354 rb_econv_t *ec;
02355 rb_transcoding *last_tc;
02356 rb_econv_result_t ret;
02357 unsigned char *out_start = *out_pos;
02358 const unsigned char *ptr;
02359 int max_output;
02360 VALUE exc;
02361
02362 ec = rb_econv_open_opts(src_encoding, dst_encoding, ecflags, ecopts);
02363 if (!ec)
02364 rb_exc_raise(rb_econv_open_exc(src_encoding, dst_encoding, ecflags));
02365
02366 last_tc = ec->last_tc;
02367 max_output = last_tc ? last_tc->transcoder->max_output : 1;
02368
02369 ret = econv_source_buffer_empty;
02370 ptr = *in_pos;
02371 while (ret != econv_finished) {
02372 unsigned char input_byte;
02373 const unsigned char *p = &input_byte;
02374
02375 if (ret == econv_source_buffer_empty) {
02376 if (ptr < in_stop) {
02377 input_byte = *ptr;
02378 ret = rb_econv_convert(ec, &p, p+1, out_pos, out_stop, ECONV_PARTIAL_INPUT);
02379 }
02380 else {
02381 ret = rb_econv_convert(ec, NULL, NULL, out_pos, out_stop, 0);
02382 }
02383 }
02384 else {
02385 ret = rb_econv_convert(ec, NULL, NULL, out_pos, out_stop, ECONV_PARTIAL_INPUT);
02386 }
02387 if (&input_byte != p)
02388 ptr += p - &input_byte;
02389 switch (ret) {
02390 case econv_invalid_byte_sequence:
02391 case econv_incomplete_input:
02392 case econv_undefined_conversion:
02393 exc = make_econv_exception(ec);
02394 rb_econv_close(ec);
02395 rb_exc_raise(exc);
02396 break;
02397
02398 case econv_destination_buffer_full:
02399 more_output_buffer(destination, resize_destination, max_output, &out_start, out_pos, &out_stop);
02400 break;
02401
02402 case econv_source_buffer_empty:
02403 break;
02404
02405 case econv_finished:
02406 break;
02407 }
02408 }
02409 rb_econv_close(ec);
02410 *in_pos = in_stop;
02411 return;
02412 }
02413 #endif
02414
02415
02416
02417
02418
02419
02420 static unsigned char *
02421 str_transcoding_resize(VALUE destination, size_t len, size_t new_len)
02422 {
02423 rb_str_resize(destination, new_len);
02424 return (unsigned char *)RSTRING_PTR(destination);
02425 }
02426
02427 static int
02428 econv_opts(VALUE opt, int ecflags)
02429 {
02430 VALUE v;
02431
02432 v = rb_hash_aref(opt, sym_invalid);
02433 if (NIL_P(v)) {
02434 }
02435 else if (v==sym_replace) {
02436 ecflags |= ECONV_INVALID_REPLACE;
02437 }
02438 else {
02439 rb_raise(rb_eArgError, "unknown value for invalid character option");
02440 }
02441
02442 v = rb_hash_aref(opt, sym_undef);
02443 if (NIL_P(v)) {
02444 }
02445 else if (v==sym_replace) {
02446 ecflags |= ECONV_UNDEF_REPLACE;
02447 }
02448 else {
02449 rb_raise(rb_eArgError, "unknown value for undefined character option");
02450 }
02451
02452 v = rb_hash_aref(opt, sym_replace);
02453 if (!NIL_P(v) && !(ecflags & ECONV_INVALID_REPLACE)) {
02454 ecflags |= ECONV_UNDEF_REPLACE;
02455 }
02456
02457 v = rb_hash_aref(opt, sym_xml);
02458 if (!NIL_P(v)) {
02459 if (v==sym_text) {
02460 ecflags |= ECONV_XML_TEXT_DECORATOR|ECONV_UNDEF_HEX_CHARREF;
02461 }
02462 else if (v==sym_attr) {
02463 ecflags |= ECONV_XML_ATTR_CONTENT_DECORATOR|ECONV_XML_ATTR_QUOTE_DECORATOR|ECONV_UNDEF_HEX_CHARREF;
02464 }
02465 else if (RB_TYPE_P(v, T_SYMBOL)) {
02466 rb_raise(rb_eArgError, "unexpected value for xml option: %s", rb_id2name(SYM2ID(v)));
02467 }
02468 else {
02469 rb_raise(rb_eArgError, "unexpected value for xml option");
02470 }
02471 }
02472
02473 #ifdef ENABLE_ECONV_NEWLINE_OPTION
02474 v = rb_hash_aref(opt, sym_newline);
02475 if (!NIL_P(v)) {
02476 ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
02477 if (v == sym_universal) {
02478 ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
02479 }
02480 else if (v == sym_crlf) {
02481 ecflags |= ECONV_CRLF_NEWLINE_DECORATOR;
02482 }
02483 else if (v == sym_cr) {
02484 ecflags |= ECONV_CR_NEWLINE_DECORATOR;
02485 }
02486 else if (v == sym_lf) {
02487
02488 }
02489 else if (SYMBOL_P(v)) {
02490 rb_raise(rb_eArgError, "unexpected value for newline option: %s",
02491 rb_id2name(SYM2ID(v)));
02492 }
02493 else {
02494 rb_raise(rb_eArgError, "unexpected value for newline option");
02495 }
02496 }
02497 else
02498 #endif
02499 {
02500 int setflags = 0, newlineflag = 0;
02501
02502 v = rb_hash_aref(opt, sym_universal_newline);
02503 if (RTEST(v))
02504 setflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
02505 newlineflag |= !NIL_P(v);
02506
02507 v = rb_hash_aref(opt, sym_crlf_newline);
02508 if (RTEST(v))
02509 setflags |= ECONV_CRLF_NEWLINE_DECORATOR;
02510 newlineflag |= !NIL_P(v);
02511
02512 v = rb_hash_aref(opt, sym_cr_newline);
02513 if (RTEST(v))
02514 setflags |= ECONV_CR_NEWLINE_DECORATOR;
02515 newlineflag |= !NIL_P(v);
02516
02517 if (newlineflag) {
02518 ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
02519 ecflags |= setflags;
02520 }
02521 }
02522
02523 return ecflags;
02524 }
02525
02526 int
02527 rb_econv_prepare_options(VALUE opthash, VALUE *opts, int ecflags)
02528 {
02529 VALUE newhash = Qnil;
02530 VALUE v;
02531
02532 if (NIL_P(opthash)) {
02533 *opts = Qnil;
02534 return ecflags;
02535 }
02536 ecflags = econv_opts(opthash, ecflags);
02537
02538 v = rb_hash_aref(opthash, sym_replace);
02539 if (!NIL_P(v)) {
02540 StringValue(v);
02541 if (rb_enc_str_coderange(v) == ENC_CODERANGE_BROKEN) {
02542 VALUE dumped = rb_str_dump(v);
02543 rb_raise(rb_eArgError, "replacement string is broken: %s as %s",
02544 StringValueCStr(dumped),
02545 rb_enc_name(rb_enc_get(v)));
02546 }
02547 v = rb_str_new_frozen(v);
02548 newhash = rb_hash_new();
02549 rb_hash_aset(newhash, sym_replace, v);
02550 }
02551
02552 v = rb_hash_aref(opthash, sym_fallback);
02553 if (!NIL_P(v)) {
02554 VALUE h = rb_check_hash_type(v);
02555 if (NIL_P(h)
02556 ? (rb_obj_is_proc(v) || rb_obj_is_method(v) || rb_respond_to(v, sym_aref))
02557 : (v = h, 1)) {
02558 if (NIL_P(newhash))
02559 newhash = rb_hash_new();
02560 rb_hash_aset(newhash, sym_fallback, v);
02561 }
02562 }
02563
02564 if (!NIL_P(newhash))
02565 rb_hash_freeze(newhash);
02566 *opts = newhash;
02567
02568 return ecflags;
02569 }
02570
02571 int
02572 rb_econv_prepare_opts(VALUE opthash, VALUE *opts)
02573 {
02574 return rb_econv_prepare_options(opthash, opts, 0);
02575 }
02576
02577 rb_econv_t *
02578 rb_econv_open_opts(const char *source_encoding, const char *destination_encoding, int ecflags, VALUE opthash)
02579 {
02580 rb_econv_t *ec;
02581 VALUE replacement;
02582
02583 if (NIL_P(opthash)) {
02584 replacement = Qnil;
02585 }
02586 else {
02587 if (!RB_TYPE_P(opthash, T_HASH) || !OBJ_FROZEN(opthash))
02588 rb_bug("rb_econv_open_opts called with invalid opthash");
02589 replacement = rb_hash_aref(opthash, sym_replace);
02590 }
02591
02592 ec = rb_econv_open(source_encoding, destination_encoding, ecflags);
02593 if (!ec)
02594 return ec;
02595
02596 if (!NIL_P(replacement)) {
02597 int ret;
02598 rb_encoding *enc = rb_enc_get(replacement);
02599
02600 ret = rb_econv_set_replacement(ec,
02601 (const unsigned char *)RSTRING_PTR(replacement),
02602 RSTRING_LEN(replacement),
02603 rb_enc_name(enc));
02604 if (ret == -1) {
02605 rb_econv_close(ec);
02606 return NULL;
02607 }
02608 }
02609 return ec;
02610 }
02611
02612 static int
02613 enc_arg(volatile VALUE *arg, const char **name_p, rb_encoding **enc_p)
02614 {
02615 rb_encoding *enc;
02616 const char *n;
02617 int encidx;
02618 VALUE encval;
02619
02620 if (((encidx = rb_to_encoding_index(encval = *arg)) < 0) ||
02621 !(enc = rb_enc_from_index(encidx))) {
02622 enc = NULL;
02623 encidx = 0;
02624 n = StringValueCStr(*arg);
02625 }
02626 else {
02627 n = rb_enc_name(enc);
02628 }
02629
02630 *name_p = n;
02631 *enc_p = enc;
02632
02633 return encidx;
02634 }
02635
02636 static int
02637 str_transcode_enc_args(VALUE str, volatile VALUE *arg1, volatile VALUE *arg2,
02638 const char **sname_p, rb_encoding **senc_p,
02639 const char **dname_p, rb_encoding **denc_p)
02640 {
02641 rb_encoding *senc, *denc;
02642 const char *sname, *dname;
02643 int sencidx, dencidx;
02644
02645 dencidx = enc_arg(arg1, &dname, &denc);
02646
02647 if (NIL_P(*arg2)) {
02648 sencidx = rb_enc_get_index(str);
02649 senc = rb_enc_from_index(sencidx);
02650 sname = rb_enc_name(senc);
02651 }
02652 else {
02653 sencidx = enc_arg(arg2, &sname, &senc);
02654 }
02655
02656 *sname_p = sname;
02657 *senc_p = senc;
02658 *dname_p = dname;
02659 *denc_p = denc;
02660 return dencidx;
02661 }
02662
02663 static int
02664 str_transcode0(int argc, VALUE *argv, VALUE *self, int ecflags, VALUE ecopts)
02665 {
02666 VALUE dest;
02667 VALUE str = *self;
02668 volatile VALUE arg1, arg2;
02669 long blen, slen;
02670 unsigned char *buf, *bp, *sp;
02671 const unsigned char *fromp;
02672 rb_encoding *senc, *denc;
02673 const char *sname, *dname;
02674 int dencidx;
02675 int explicitly_invalid_replace = TRUE;
02676
02677 rb_check_arity(argc, 0, 2);
02678
02679 if (argc == 0) {
02680 arg1 = rb_enc_default_internal();
02681 if (NIL_P(arg1)) {
02682 if (!ecflags) return -1;
02683 arg1 = rb_obj_encoding(str);
02684 }
02685 if (!(ecflags & ECONV_INVALID_MASK)) {
02686 explicitly_invalid_replace = FALSE;
02687 }
02688 ecflags |= ECONV_INVALID_REPLACE | ECONV_UNDEF_REPLACE;
02689 }
02690 else {
02691 arg1 = argv[0];
02692 }
02693 arg2 = argc<=1 ? Qnil : argv[1];
02694 dencidx = str_transcode_enc_args(str, &arg1, &arg2, &sname, &senc, &dname, &denc);
02695
02696 if ((ecflags & (ECONV_NEWLINE_DECORATOR_MASK|
02697 ECONV_XML_TEXT_DECORATOR|
02698 ECONV_XML_ATTR_CONTENT_DECORATOR|
02699 ECONV_XML_ATTR_QUOTE_DECORATOR)) == 0) {
02700 if (senc && senc == denc) {
02701 if ((ecflags & ECONV_INVALID_MASK) && explicitly_invalid_replace) {
02702 VALUE rep = Qnil;
02703 if (!NIL_P(ecopts)) {
02704 rep = rb_hash_aref(ecopts, sym_replace);
02705 }
02706 dest = rb_str_scrub(str, rep);
02707 if (NIL_P(dest)) dest = str;
02708 *self = dest;
02709 return dencidx;
02710 }
02711 return NIL_P(arg2) ? -1 : dencidx;
02712 }
02713 if (senc && denc && rb_enc_asciicompat(senc) && rb_enc_asciicompat(denc)) {
02714 if (rb_enc_str_coderange(str) == ENC_CODERANGE_7BIT) {
02715 return dencidx;
02716 }
02717 }
02718 if (encoding_equal(sname, dname)) {
02719 return NIL_P(arg2) ? -1 : dencidx;
02720 }
02721 }
02722 else {
02723 if (encoding_equal(sname, dname)) {
02724 sname = "";
02725 dname = "";
02726 }
02727 }
02728
02729 fromp = sp = (unsigned char *)RSTRING_PTR(str);
02730 slen = RSTRING_LEN(str);
02731 blen = slen + 30;
02732 dest = rb_str_tmp_new(blen);
02733 bp = (unsigned char *)RSTRING_PTR(dest);
02734
02735 transcode_loop(&fromp, &bp, (sp+slen), (bp+blen), dest, str_transcoding_resize, sname, dname, ecflags, ecopts);
02736 if (fromp != sp+slen) {
02737 rb_raise(rb_eArgError, "not fully converted, %"PRIdPTRDIFF" bytes left", sp+slen-fromp);
02738 }
02739 buf = (unsigned char *)RSTRING_PTR(dest);
02740 *bp = '\0';
02741 rb_str_set_len(dest, bp - buf);
02742
02743
02744 if (!denc) {
02745 dencidx = rb_define_dummy_encoding(dname);
02746 }
02747 *self = dest;
02748
02749 return dencidx;
02750 }
02751
02752 static int
02753 str_transcode(int argc, VALUE *argv, VALUE *self)
02754 {
02755 VALUE opt;
02756 int ecflags = 0;
02757 VALUE ecopts = Qnil;
02758
02759 argc = rb_scan_args(argc, argv, "02:", NULL, NULL, &opt);
02760 if (!NIL_P(opt)) {
02761 ecflags = rb_econv_prepare_opts(opt, &ecopts);
02762 }
02763 return str_transcode0(argc, argv, self, ecflags, ecopts);
02764 }
02765
02766 static inline VALUE
02767 str_encode_associate(VALUE str, int encidx)
02768 {
02769 int cr = 0;
02770
02771 rb_enc_associate_index(str, encidx);
02772
02773
02774 if (rb_enc_asciicompat(rb_enc_from_index(encidx))) {
02775 rb_str_coderange_scan_restartable(RSTRING_PTR(str), RSTRING_END(str), 0, &cr);
02776 }
02777 else {
02778 cr = ENC_CODERANGE_VALID;
02779 }
02780 ENC_CODERANGE_SET(str, cr);
02781 return str;
02782 }
02783
02784
02785
02786
02787
02788
02789
02790
02791
02792
02793
02794
02795
02796
02797
02798 static VALUE
02799 str_encode_bang(int argc, VALUE *argv, VALUE str)
02800 {
02801 VALUE newstr;
02802 int encidx;
02803
02804 rb_check_frozen(str);
02805
02806 newstr = str;
02807 encidx = str_transcode(argc, argv, &newstr);
02808
02809 if (encidx < 0) return str;
02810 if (newstr == str) {
02811 rb_enc_associate_index(str, encidx);
02812 return str;
02813 }
02814 rb_str_shared_replace(str, newstr);
02815 return str_encode_associate(str, encidx);
02816 }
02817
02818 static VALUE encoded_dup(VALUE newstr, VALUE str, int encidx);
02819
02820
02821
02822
02823
02824
02825
02826
02827
02828
02829
02830
02831
02832
02833
02834
02835
02836
02837
02838
02839
02840
02841
02842
02843
02844
02845
02846
02847
02848
02849
02850
02851
02852
02853
02854
02855
02856
02857
02858
02859
02860
02861
02862
02863
02864
02865
02866
02867
02868
02869
02870
02871
02872
02873
02874
02875
02876 static VALUE
02877 str_encode(int argc, VALUE *argv, VALUE str)
02878 {
02879 VALUE newstr = str;
02880 int encidx = str_transcode(argc, argv, &newstr);
02881 return encoded_dup(newstr, str, encidx);
02882 }
02883
02884 VALUE
02885 rb_str_encode(VALUE str, VALUE to, int ecflags, VALUE ecopts)
02886 {
02887 int argc = 1;
02888 VALUE *argv = &to;
02889 VALUE newstr = str;
02890 int encidx = str_transcode0(argc, argv, &newstr, ecflags, ecopts);
02891 return encoded_dup(newstr, str, encidx);
02892 }
02893
02894 static VALUE
02895 encoded_dup(VALUE newstr, VALUE str, int encidx)
02896 {
02897 if (encidx < 0) return rb_str_dup(str);
02898 if (newstr == str) {
02899 newstr = rb_str_dup(str);
02900 rb_enc_associate_index(newstr, encidx);
02901 return newstr;
02902 }
02903 else {
02904 RBASIC_SET_CLASS(newstr, rb_obj_class(str));
02905 }
02906 return str_encode_associate(newstr, encidx);
02907 }
02908
02909 static void
02910 econv_free(void *ptr)
02911 {
02912 rb_econv_t *ec = ptr;
02913 rb_econv_close(ec);
02914 }
02915
02916 static size_t
02917 econv_memsize(const void *ptr)
02918 {
02919 return ptr ? sizeof(rb_econv_t) : 0;
02920 }
02921
02922 static const rb_data_type_t econv_data_type = {
02923 "econv",
02924 {NULL, econv_free, econv_memsize,},
02925 NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY
02926 };
02927
02928 static VALUE
02929 econv_s_allocate(VALUE klass)
02930 {
02931 return TypedData_Wrap_Struct(klass, &econv_data_type, NULL);
02932 }
02933
02934 static rb_encoding *
02935 make_dummy_encoding(const char *name)
02936 {
02937 rb_encoding *enc;
02938 int idx;
02939 idx = rb_define_dummy_encoding(name);
02940 enc = rb_enc_from_index(idx);
02941 return enc;
02942 }
02943
02944 static rb_encoding *
02945 make_encoding(const char *name)
02946 {
02947 rb_encoding *enc;
02948 enc = rb_enc_find(name);
02949 if (!enc)
02950 enc = make_dummy_encoding(name);
02951 return enc;
02952 }
02953
02954 static VALUE
02955 make_encobj(const char *name)
02956 {
02957 return rb_enc_from_encoding(make_encoding(name));
02958 }
02959
02960
02961
02962
02963
02964
02965
02966
02967
02968
02969
02970
02971
02972
02973
02974
02975
02976
02977
02978 static VALUE
02979 econv_s_asciicompat_encoding(VALUE klass, VALUE arg)
02980 {
02981 const char *arg_name, *result_name;
02982 rb_encoding *arg_enc, *result_enc;
02983
02984 enc_arg(&arg, &arg_name, &arg_enc);
02985
02986 result_name = rb_econv_asciicompat_encoding(arg_name);
02987
02988 if (result_name == NULL)
02989 return Qnil;
02990
02991 result_enc = make_encoding(result_name);
02992
02993 return rb_enc_from_encoding(result_enc);
02994 }
02995
02996 static void
02997 econv_args(int argc, VALUE *argv,
02998 volatile VALUE *snamev_p, volatile VALUE *dnamev_p,
02999 const char **sname_p, const char **dname_p,
03000 rb_encoding **senc_p, rb_encoding **denc_p,
03001 int *ecflags_p,
03002 VALUE *ecopts_p)
03003 {
03004 VALUE opt, flags_v, ecopts;
03005 int sidx, didx;
03006 const char *sname, *dname;
03007 rb_encoding *senc, *denc;
03008 int ecflags;
03009
03010 argc = rb_scan_args(argc, argv, "21:", snamev_p, dnamev_p, &flags_v, &opt);
03011
03012 if (!NIL_P(flags_v)) {
03013 if (!NIL_P(opt)) {
03014 rb_error_arity(argc + 1, 2, 3);
03015 }
03016 ecflags = NUM2INT(rb_to_int(flags_v));
03017 ecopts = Qnil;
03018 }
03019 else if (!NIL_P(opt)) {
03020 ecflags = rb_econv_prepare_opts(opt, &ecopts);
03021 }
03022 else {
03023 ecflags = 0;
03024 ecopts = Qnil;
03025 }
03026
03027 senc = NULL;
03028 sidx = rb_to_encoding_index(*snamev_p);
03029 if (0 <= sidx) {
03030 senc = rb_enc_from_index(sidx);
03031 }
03032 else {
03033 StringValue(*snamev_p);
03034 }
03035
03036 denc = NULL;
03037 didx = rb_to_encoding_index(*dnamev_p);
03038 if (0 <= didx) {
03039 denc = rb_enc_from_index(didx);
03040 }
03041 else {
03042 StringValue(*dnamev_p);
03043 }
03044
03045 sname = senc ? rb_enc_name(senc) : StringValueCStr(*snamev_p);
03046 dname = denc ? rb_enc_name(denc) : StringValueCStr(*dnamev_p);
03047
03048 *sname_p = sname;
03049 *dname_p = dname;
03050 *senc_p = senc;
03051 *denc_p = denc;
03052 *ecflags_p = ecflags;
03053 *ecopts_p = ecopts;
03054 }
03055
03056 static int
03057 decorate_convpath(VALUE convpath, int ecflags)
03058 {
03059 int num_decorators;
03060 const char *decorators[MAX_ECFLAGS_DECORATORS];
03061 int i;
03062 int n, len;
03063
03064 num_decorators = decorator_names(ecflags, decorators);
03065 if (num_decorators == -1)
03066 return -1;
03067
03068 len = n = RARRAY_LENINT(convpath);
03069 if (n != 0) {
03070 VALUE pair = RARRAY_AREF(convpath, n-1);
03071 if (RB_TYPE_P(pair, T_ARRAY)) {
03072 const char *sname = rb_enc_name(rb_to_encoding(RARRAY_AREF(pair, 0)));
03073 const char *dname = rb_enc_name(rb_to_encoding(RARRAY_AREF(pair, 1)));
03074 transcoder_entry_t *entry = get_transcoder_entry(sname, dname);
03075 const rb_transcoder *tr = load_transcoder_entry(entry);
03076 if (!tr)
03077 return -1;
03078 if (!DECORATOR_P(tr->src_encoding, tr->dst_encoding) &&
03079 tr->asciicompat_type == asciicompat_encoder) {
03080 n--;
03081 rb_ary_store(convpath, len + num_decorators - 1, pair);
03082 }
03083 }
03084 else {
03085 rb_ary_store(convpath, len + num_decorators - 1, pair);
03086 }
03087 }
03088
03089 for (i = 0; i < num_decorators; i++)
03090 rb_ary_store(convpath, n + i, rb_str_new_cstr(decorators[i]));
03091
03092 return 0;
03093 }
03094
03095 static void
03096 search_convpath_i(const char *sname, const char *dname, int depth, void *arg)
03097 {
03098 VALUE *ary_p = arg;
03099 VALUE v;
03100
03101 if (*ary_p == Qnil) {
03102 *ary_p = rb_ary_new();
03103 }
03104
03105 if (DECORATOR_P(sname, dname)) {
03106 v = rb_str_new_cstr(dname);
03107 }
03108 else {
03109 v = rb_assoc_new(make_encobj(sname), make_encobj(dname));
03110 }
03111 rb_ary_store(*ary_p, depth, v);
03112 }
03113
03114
03115
03116
03117
03118
03119
03120
03121
03122
03123
03124
03125
03126
03127
03128
03129
03130
03131
03132
03133
03134
03135
03136
03137
03138
03139 static VALUE
03140 econv_s_search_convpath(int argc, VALUE *argv, VALUE klass)
03141 {
03142 volatile VALUE snamev, dnamev;
03143 const char *sname, *dname;
03144 rb_encoding *senc, *denc;
03145 int ecflags;
03146 VALUE ecopts;
03147 VALUE convpath;
03148
03149 econv_args(argc, argv, &snamev, &dnamev, &sname, &dname, &senc, &denc, &ecflags, &ecopts);
03150
03151 convpath = Qnil;
03152 transcode_search_path(sname, dname, search_convpath_i, &convpath);
03153
03154 if (NIL_P(convpath))
03155 rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
03156
03157 if (decorate_convpath(convpath, ecflags) == -1)
03158 rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
03159
03160 return convpath;
03161 }
03162
03163
03164
03165
03166
03167
03168 int
03169 rb_econv_has_convpath_p(const char* from_encoding, const char* to_encoding)
03170 {
03171 VALUE convpath = Qnil;
03172 transcode_search_path(from_encoding, to_encoding, search_convpath_i,
03173 &convpath);
03174 return RTEST(convpath);
03175 }
03176
03177 struct rb_econv_init_by_convpath_t {
03178 rb_econv_t *ec;
03179 int index;
03180 int ret;
03181 };
03182
03183 static void
03184 rb_econv_init_by_convpath_i(const char *sname, const char *dname, int depth, void *arg)
03185 {
03186 struct rb_econv_init_by_convpath_t *a = (struct rb_econv_init_by_convpath_t *)arg;
03187 int ret;
03188
03189 if (a->ret == -1)
03190 return;
03191
03192 ret = rb_econv_add_converter(a->ec, sname, dname, a->index);
03193
03194 a->ret = ret;
03195 return;
03196 }
03197
03198 static rb_econv_t *
03199 rb_econv_init_by_convpath(VALUE self, VALUE convpath,
03200 const char **sname_p, const char **dname_p,
03201 rb_encoding **senc_p, rb_encoding**denc_p)
03202 {
03203 rb_econv_t *ec;
03204 long i;
03205 int ret, first=1;
03206 VALUE elt;
03207 rb_encoding *senc = 0, *denc = 0;
03208 const char *sname, *dname;
03209
03210 ec = rb_econv_alloc(RARRAY_LENINT(convpath));
03211 DATA_PTR(self) = ec;
03212
03213 for (i = 0; i < RARRAY_LEN(convpath); i++) {
03214 volatile VALUE snamev, dnamev;
03215 VALUE pair;
03216 elt = rb_ary_entry(convpath, i);
03217 if (!NIL_P(pair = rb_check_array_type(elt))) {
03218 if (RARRAY_LEN(pair) != 2)
03219 rb_raise(rb_eArgError, "not a 2-element array in convpath");
03220 snamev = rb_ary_entry(pair, 0);
03221 enc_arg(&snamev, &sname, &senc);
03222 dnamev = rb_ary_entry(pair, 1);
03223 enc_arg(&dnamev, &dname, &denc);
03224 }
03225 else {
03226 sname = "";
03227 dname = StringValueCStr(elt);
03228 }
03229 if (DECORATOR_P(sname, dname)) {
03230 ret = rb_econv_add_converter(ec, sname, dname, ec->num_trans);
03231 if (ret == -1)
03232 rb_raise(rb_eArgError, "decoration failed: %s", dname);
03233 }
03234 else {
03235 int j = ec->num_trans;
03236 struct rb_econv_init_by_convpath_t arg;
03237 arg.ec = ec;
03238 arg.index = ec->num_trans;
03239 arg.ret = 0;
03240 ret = transcode_search_path(sname, dname, rb_econv_init_by_convpath_i, &arg);
03241 if (ret == -1 || arg.ret == -1)
03242 rb_raise(rb_eArgError, "adding conversion failed: %s to %s", sname, dname);
03243 if (first) {
03244 first = 0;
03245 *senc_p = senc;
03246 *sname_p = ec->elems[j].tc->transcoder->src_encoding;
03247 }
03248 *denc_p = denc;
03249 *dname_p = ec->elems[ec->num_trans-1].tc->transcoder->dst_encoding;
03250 }
03251 }
03252
03253 if (first) {
03254 *senc_p = NULL;
03255 *denc_p = NULL;
03256 *sname_p = "";
03257 *dname_p = "";
03258 }
03259
03260 ec->source_encoding_name = *sname_p;
03261 ec->destination_encoding_name = *dname_p;
03262
03263 return ec;
03264 }
03265
03266
03267
03268
03269
03270
03271
03272
03273
03274
03275
03276
03277
03278
03279
03280
03281
03282
03283
03284
03285
03286
03287
03288
03289
03290
03291
03292
03293
03294
03295
03296
03297
03298
03299
03300
03301
03302
03303
03304
03305
03306
03307
03308
03309
03310
03311
03312
03313
03314
03315
03316
03317
03318
03319
03320
03321
03322
03323
03324
03325
03326
03327
03328
03329
03330
03331
03332
03333
03334
03335
03336
03337
03338
03339
03340
03341
03342
03343
03344
03345
03346
03347
03348
03349
03350
03351
03352
03353
03354
03355
03356
03357
03358
03359
03360
03361
03362
03363
03364
03365
03366
03367
03368
03369
03370
03371
03372 static VALUE
03373 econv_init(int argc, VALUE *argv, VALUE self)
03374 {
03375 VALUE ecopts;
03376 volatile VALUE snamev, dnamev;
03377 const char *sname, *dname;
03378 rb_encoding *senc, *denc;
03379 rb_econv_t *ec;
03380 int ecflags;
03381 VALUE convpath;
03382
03383 if (rb_check_typeddata(self, &econv_data_type)) {
03384 rb_raise(rb_eTypeError, "already initialized");
03385 }
03386
03387 if (argc == 1 && !NIL_P(convpath = rb_check_array_type(argv[0]))) {
03388 ec = rb_econv_init_by_convpath(self, convpath, &sname, &dname, &senc, &denc);
03389 ecflags = 0;
03390 ecopts = Qnil;
03391 }
03392 else {
03393 econv_args(argc, argv, &snamev, &dnamev, &sname, &dname, &senc, &denc, &ecflags, &ecopts);
03394 ec = rb_econv_open_opts(sname, dname, ecflags, ecopts);
03395 }
03396
03397 if (!ec) {
03398 rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
03399 }
03400
03401 if (!DECORATOR_P(sname, dname)) {
03402 if (!senc)
03403 senc = make_dummy_encoding(sname);
03404 if (!denc)
03405 denc = make_dummy_encoding(dname);
03406 }
03407
03408 ec->source_encoding = senc;
03409 ec->destination_encoding = denc;
03410
03411 DATA_PTR(self) = ec;
03412
03413 return self;
03414 }
03415
03416
03417
03418
03419
03420
03421
03422
03423
03424
03425
03426 static VALUE
03427 econv_inspect(VALUE self)
03428 {
03429 const char *cname = rb_obj_classname(self);
03430 rb_econv_t *ec;
03431
03432 TypedData_Get_Struct(self, rb_econv_t, &econv_data_type, ec);
03433 if (!ec)
03434 return rb_sprintf("#<%s: uninitialized>", cname);
03435 else {
03436 const char *sname = ec->source_encoding_name;
03437 const char *dname = ec->destination_encoding_name;
03438 VALUE str;
03439 str = rb_sprintf("#<%s: ", cname);
03440 econv_description(sname, dname, ec->flags, str);
03441 rb_str_cat2(str, ">");
03442 return str;
03443 }
03444 }
03445
03446 static rb_econv_t *
03447 check_econv(VALUE self)
03448 {
03449 rb_econv_t *ec;
03450
03451 TypedData_Get_Struct(self, rb_econv_t, &econv_data_type, ec);
03452 if (!ec) {
03453 rb_raise(rb_eTypeError, "uninitialized encoding converter");
03454 }
03455 return ec;
03456 }
03457
03458
03459
03460
03461
03462
03463
03464 static VALUE
03465 econv_source_encoding(VALUE self)
03466 {
03467 rb_econv_t *ec = check_econv(self);
03468 if (!ec->source_encoding)
03469 return Qnil;
03470 return rb_enc_from_encoding(ec->source_encoding);
03471 }
03472
03473
03474
03475
03476
03477
03478
03479 static VALUE
03480 econv_destination_encoding(VALUE self)
03481 {
03482 rb_econv_t *ec = check_econv(self);
03483 if (!ec->destination_encoding)
03484 return Qnil;
03485 return rb_enc_from_encoding(ec->destination_encoding);
03486 }
03487
03488
03489
03490
03491
03492
03493
03494
03495
03496
03497
03498
03499
03500
03501
03502
03503
03504
03505
03506
03507
03508
03509
03510 static VALUE
03511 econv_convpath(VALUE self)
03512 {
03513 rb_econv_t *ec = check_econv(self);
03514 VALUE result;
03515 int i;
03516
03517 result = rb_ary_new();
03518 for (i = 0; i < ec->num_trans; i++) {
03519 const rb_transcoder *tr = ec->elems[i].tc->transcoder;
03520 VALUE v;
03521 if (DECORATOR_P(tr->src_encoding, tr->dst_encoding))
03522 v = rb_str_new_cstr(tr->dst_encoding);
03523 else
03524 v = rb_assoc_new(make_encobj(tr->src_encoding), make_encobj(tr->dst_encoding));
03525 rb_ary_push(result, v);
03526 }
03527 return result;
03528 }
03529
03530
03531
03532
03533
03534 static VALUE
03535 econv_equal(VALUE self, VALUE other)
03536 {
03537 rb_econv_t *ec1 = check_econv(self);
03538 rb_econv_t *ec2;
03539 int i;
03540
03541 if (!rb_typeddata_is_kind_of(other, &econv_data_type)) {
03542 return Qnil;
03543 }
03544 ec2 = DATA_PTR(other);
03545 if (!ec2) return Qfalse;
03546 if (ec1->source_encoding_name != ec2->source_encoding_name &&
03547 strcmp(ec1->source_encoding_name, ec2->source_encoding_name))
03548 return Qfalse;
03549 if (ec1->destination_encoding_name != ec2->destination_encoding_name &&
03550 strcmp(ec1->destination_encoding_name, ec2->destination_encoding_name))
03551 return Qfalse;
03552 if (ec1->flags != ec2->flags) return Qfalse;
03553 if (ec1->replacement_enc != ec2->replacement_enc &&
03554 strcmp(ec1->replacement_enc, ec2->replacement_enc))
03555 return Qfalse;
03556 if (ec1->replacement_len != ec2->replacement_len) return Qfalse;
03557 if (ec1->replacement_str != ec2->replacement_str &&
03558 memcmp(ec1->replacement_str, ec2->replacement_str, ec2->replacement_len))
03559 return Qfalse;
03560
03561 if (ec1->num_trans != ec2->num_trans) return Qfalse;
03562 for (i = 0; i < ec1->num_trans; i++) {
03563 if (ec1->elems[i].tc->transcoder != ec2->elems[i].tc->transcoder)
03564 return Qfalse;
03565 }
03566 return Qtrue;
03567 }
03568
03569 static VALUE
03570 econv_result_to_symbol(rb_econv_result_t res)
03571 {
03572 switch (res) {
03573 case econv_invalid_byte_sequence: return sym_invalid_byte_sequence;
03574 case econv_incomplete_input: return sym_incomplete_input;
03575 case econv_undefined_conversion: return sym_undefined_conversion;
03576 case econv_destination_buffer_full: return sym_destination_buffer_full;
03577 case econv_source_buffer_empty: return sym_source_buffer_empty;
03578 case econv_finished: return sym_finished;
03579 case econv_after_output: return sym_after_output;
03580 default: return INT2NUM(res);
03581 }
03582 }
03583
03584
03585
03586
03587
03588
03589
03590
03591
03592
03593
03594
03595
03596
03597
03598
03599
03600
03601
03602
03603
03604
03605
03606
03607
03608
03609
03610
03611
03612
03613
03614
03615
03616
03617
03618
03619
03620
03621
03622
03623
03624
03625
03626
03627
03628
03629
03630
03631
03632
03633
03634
03635
03636
03637
03638
03639
03640
03641
03642
03643
03644
03645
03646
03647
03648
03649
03650
03651
03652
03653
03654
03655
03656
03657
03658
03659
03660
03661
03662
03663
03664
03665
03666
03667
03668
03669
03670
03671
03672
03673
03674
03675
03676
03677
03678 static VALUE
03679 econv_primitive_convert(int argc, VALUE *argv, VALUE self)
03680 {
03681 VALUE input, output, output_byteoffset_v, output_bytesize_v, opt, flags_v;
03682 rb_econv_t *ec = check_econv(self);
03683 rb_econv_result_t res;
03684 const unsigned char *ip, *is;
03685 unsigned char *op, *os;
03686 long output_byteoffset, output_bytesize;
03687 unsigned long output_byteend;
03688 int flags;
03689
03690 argc = rb_scan_args(argc, argv, "23:", &input, &output, &output_byteoffset_v, &output_bytesize_v, &flags_v, &opt);
03691
03692 if (NIL_P(output_byteoffset_v))
03693 output_byteoffset = 0;
03694 else
03695 output_byteoffset = NUM2LONG(output_byteoffset_v);
03696
03697 if (NIL_P(output_bytesize_v))
03698 output_bytesize = 0;
03699 else
03700 output_bytesize = NUM2LONG(output_bytesize_v);
03701
03702 if (!NIL_P(flags_v)) {
03703 if (!NIL_P(opt)) {
03704 rb_error_arity(argc + 1, 2, 5);
03705 }
03706 flags = NUM2INT(rb_to_int(flags_v));
03707 }
03708 else if (!NIL_P(opt)) {
03709 VALUE v;
03710 flags = 0;
03711 v = rb_hash_aref(opt, sym_partial_input);
03712 if (RTEST(v))
03713 flags |= ECONV_PARTIAL_INPUT;
03714 v = rb_hash_aref(opt, sym_after_output);
03715 if (RTEST(v))
03716 flags |= ECONV_AFTER_OUTPUT;
03717 }
03718 else {
03719 flags = 0;
03720 }
03721
03722 StringValue(output);
03723 if (!NIL_P(input))
03724 StringValue(input);
03725 rb_str_modify(output);
03726
03727 if (NIL_P(output_bytesize_v)) {
03728 output_bytesize = RSTRING_EMBED_LEN_MAX;
03729 if (!NIL_P(input) && output_bytesize < RSTRING_LEN(input))
03730 output_bytesize = RSTRING_LEN(input);
03731 }
03732
03733 retry:
03734
03735 if (NIL_P(output_byteoffset_v))
03736 output_byteoffset = RSTRING_LEN(output);
03737
03738 if (output_byteoffset < 0)
03739 rb_raise(rb_eArgError, "negative output_byteoffset");
03740
03741 if (RSTRING_LEN(output) < output_byteoffset)
03742 rb_raise(rb_eArgError, "output_byteoffset too big");
03743
03744 if (output_bytesize < 0)
03745 rb_raise(rb_eArgError, "negative output_bytesize");
03746
03747 output_byteend = (unsigned long)output_byteoffset +
03748 (unsigned long)output_bytesize;
03749
03750 if (output_byteend < (unsigned long)output_byteoffset ||
03751 LONG_MAX < output_byteend)
03752 rb_raise(rb_eArgError, "output_byteoffset+output_bytesize too big");
03753
03754 if (rb_str_capacity(output) < output_byteend)
03755 rb_str_resize(output, output_byteend);
03756
03757 if (NIL_P(input)) {
03758 ip = is = NULL;
03759 }
03760 else {
03761 ip = (const unsigned char *)RSTRING_PTR(input);
03762 is = ip + RSTRING_LEN(input);
03763 }
03764
03765 op = (unsigned char *)RSTRING_PTR(output) + output_byteoffset;
03766 os = op + output_bytesize;
03767
03768 res = rb_econv_convert(ec, &ip, is, &op, os, flags);
03769 rb_str_set_len(output, op-(unsigned char *)RSTRING_PTR(output));
03770 if (!NIL_P(input))
03771 rb_str_drop_bytes(input, ip - (unsigned char *)RSTRING_PTR(input));
03772
03773 if (NIL_P(output_bytesize_v) && res == econv_destination_buffer_full) {
03774 if (LONG_MAX / 2 < output_bytesize)
03775 rb_raise(rb_eArgError, "too long conversion result");
03776 output_bytesize *= 2;
03777 output_byteoffset_v = Qnil;
03778 goto retry;
03779 }
03780
03781 if (ec->destination_encoding) {
03782 rb_enc_associate(output, ec->destination_encoding);
03783 }
03784
03785 return econv_result_to_symbol(res);
03786 }
03787
03788
03789
03790
03791
03792
03793
03794
03795
03796
03797
03798
03799
03800
03801
03802
03803
03804
03805
03806
03807
03808
03809
03810
03811
03812
03813
03814
03815
03816
03817
03818
03819
03820
03821
03822 static VALUE
03823 econv_convert(VALUE self, VALUE source_string)
03824 {
03825 VALUE ret, dst;
03826 VALUE av[5];
03827 int ac;
03828 rb_econv_t *ec = check_econv(self);
03829
03830 StringValue(source_string);
03831
03832 dst = rb_str_new(NULL, 0);
03833
03834 av[0] = rb_str_dup(source_string);
03835 av[1] = dst;
03836 av[2] = Qnil;
03837 av[3] = Qnil;
03838 av[4] = INT2NUM(ECONV_PARTIAL_INPUT);
03839 ac = 5;
03840
03841 ret = econv_primitive_convert(ac, av, self);
03842
03843 if (ret == sym_invalid_byte_sequence ||
03844 ret == sym_undefined_conversion ||
03845 ret == sym_incomplete_input) {
03846 VALUE exc = make_econv_exception(ec);
03847 rb_exc_raise(exc);
03848 }
03849
03850 if (ret == sym_finished) {
03851 rb_raise(rb_eArgError, "converter already finished");
03852 }
03853
03854 if (ret != sym_source_buffer_empty) {
03855 rb_bug("unexpected result of econv_primitive_convert");
03856 }
03857
03858 return dst;
03859 }
03860
03861
03862
03863
03864
03865
03866
03867
03868
03869
03870
03871
03872 static VALUE
03873 econv_finish(VALUE self)
03874 {
03875 VALUE ret, dst;
03876 VALUE av[5];
03877 int ac;
03878 rb_econv_t *ec = check_econv(self);
03879
03880 dst = rb_str_new(NULL, 0);
03881
03882 av[0] = Qnil;
03883 av[1] = dst;
03884 av[2] = Qnil;
03885 av[3] = Qnil;
03886 av[4] = INT2FIX(0);
03887 ac = 5;
03888
03889 ret = econv_primitive_convert(ac, av, self);
03890
03891 if (ret == sym_invalid_byte_sequence ||
03892 ret == sym_undefined_conversion ||
03893 ret == sym_incomplete_input) {
03894 VALUE exc = make_econv_exception(ec);
03895 rb_exc_raise(exc);
03896 }
03897
03898 if (ret != sym_finished) {
03899 rb_bug("unexpected result of econv_primitive_convert");
03900 }
03901
03902 return dst;
03903 }
03904
03905
03906
03907
03908
03909
03910
03911
03912
03913
03914
03915
03916
03917
03918
03919
03920
03921
03922
03923
03924
03925
03926
03927
03928
03929
03930
03931
03932
03933
03934
03935
03936
03937
03938
03939
03940
03941
03942
03943
03944
03945
03946
03947
03948
03949
03950
03951
03952
03953
03954
03955
03956
03957
03958
03959
03960
03961
03962
03963
03964
03965
03966
03967
03968
03969
03970
03971
03972
03973
03974
03975
03976
03977
03978
03979
03980 static VALUE
03981 econv_primitive_errinfo(VALUE self)
03982 {
03983 rb_econv_t *ec = check_econv(self);
03984
03985 VALUE ary;
03986
03987 ary = rb_ary_new2(5);
03988
03989 rb_ary_store(ary, 0, econv_result_to_symbol(ec->last_error.result));
03990 rb_ary_store(ary, 4, Qnil);
03991
03992 if (ec->last_error.source_encoding)
03993 rb_ary_store(ary, 1, rb_str_new2(ec->last_error.source_encoding));
03994
03995 if (ec->last_error.destination_encoding)
03996 rb_ary_store(ary, 2, rb_str_new2(ec->last_error.destination_encoding));
03997
03998 if (ec->last_error.error_bytes_start) {
03999 rb_ary_store(ary, 3, rb_str_new((const char *)ec->last_error.error_bytes_start, ec->last_error.error_bytes_len));
04000 rb_ary_store(ary, 4, rb_str_new((const char *)ec->last_error.error_bytes_start + ec->last_error.error_bytes_len, ec->last_error.readagain_len));
04001 }
04002
04003 return ary;
04004 }
04005
04006
04007
04008
04009
04010
04011
04012
04013
04014
04015
04016
04017
04018
04019
04020
04021
04022
04023
04024
04025
04026
04027
04028
04029
04030
04031
04032
04033
04034
04035
04036
04037
04038 static VALUE
04039 econv_insert_output(VALUE self, VALUE string)
04040 {
04041 const char *insert_enc;
04042
04043 int ret;
04044
04045 rb_econv_t *ec = check_econv(self);
04046
04047 StringValue(string);
04048 insert_enc = rb_econv_encoding_to_insert_output(ec);
04049 string = rb_str_encode(string, rb_enc_from_encoding(rb_enc_find(insert_enc)), 0, Qnil);
04050
04051 ret = rb_econv_insert_output(ec, (const unsigned char *)RSTRING_PTR(string), RSTRING_LEN(string), insert_enc);
04052 if (ret == -1) {
04053 rb_raise(rb_eArgError, "too big string");
04054 }
04055
04056 return Qnil;
04057 }
04058
04059
04060
04061
04062
04063
04064
04065
04066
04067
04068
04069
04070
04071
04072
04073
04074
04075
04076
04077
04078
04079
04080
04081
04082
04083 static VALUE
04084 econv_putback(int argc, VALUE *argv, VALUE self)
04085 {
04086 rb_econv_t *ec = check_econv(self);
04087 int n;
04088 int putbackable;
04089 VALUE str, max;
04090
04091 rb_scan_args(argc, argv, "01", &max);
04092
04093 if (NIL_P(max))
04094 n = rb_econv_putbackable(ec);
04095 else {
04096 n = NUM2INT(max);
04097 putbackable = rb_econv_putbackable(ec);
04098 if (putbackable < n)
04099 n = putbackable;
04100 }
04101
04102 str = rb_str_new(NULL, n);
04103 rb_econv_putback(ec, (unsigned char *)RSTRING_PTR(str), n);
04104
04105 if (ec->source_encoding) {
04106 rb_enc_associate(str, ec->source_encoding);
04107 }
04108
04109 return str;
04110 }
04111
04112
04113
04114
04115
04116
04117
04118
04119
04120
04121
04122
04123
04124
04125
04126
04127
04128
04129
04130
04131
04132 static VALUE
04133 econv_last_error(VALUE self)
04134 {
04135 rb_econv_t *ec = check_econv(self);
04136 VALUE exc;
04137
04138 exc = make_econv_exception(ec);
04139 if (NIL_P(exc))
04140 return Qnil;
04141 return exc;
04142 }
04143
04144
04145
04146
04147
04148
04149
04150
04151
04152
04153
04154
04155
04156 static VALUE
04157 econv_get_replacement(VALUE self)
04158 {
04159 rb_econv_t *ec = check_econv(self);
04160 int ret;
04161 rb_encoding *enc;
04162
04163 ret = make_replacement(ec);
04164 if (ret == -1) {
04165 rb_raise(rb_eUndefinedConversionError, "replacement character setup failed");
04166 }
04167
04168 enc = rb_enc_find(ec->replacement_enc);
04169 return rb_enc_str_new((const char *)ec->replacement_str, (long)ec->replacement_len, enc);
04170 }
04171
04172
04173
04174
04175
04176
04177
04178
04179
04180
04181
04182 static VALUE
04183 econv_set_replacement(VALUE self, VALUE arg)
04184 {
04185 rb_econv_t *ec = check_econv(self);
04186 VALUE string = arg;
04187 int ret;
04188 rb_encoding *enc;
04189
04190 StringValue(string);
04191 enc = rb_enc_get(string);
04192
04193 ret = rb_econv_set_replacement(ec,
04194 (const unsigned char *)RSTRING_PTR(string),
04195 RSTRING_LEN(string),
04196 rb_enc_name(enc));
04197
04198 if (ret == -1) {
04199
04200 rb_raise(rb_eUndefinedConversionError, "replacement character setup failed");
04201 }
04202
04203 return arg;
04204 }
04205
04206 VALUE
04207 rb_econv_make_exception(rb_econv_t *ec)
04208 {
04209 return make_econv_exception(ec);
04210 }
04211
04212 void
04213 rb_econv_check_error(rb_econv_t *ec)
04214 {
04215 VALUE exc;
04216
04217 exc = make_econv_exception(ec);
04218 if (NIL_P(exc))
04219 return;
04220 rb_exc_raise(exc);
04221 }
04222
04223
04224
04225
04226
04227
04228
04229 static VALUE
04230 ecerr_source_encoding_name(VALUE self)
04231 {
04232 return rb_attr_get(self, rb_intern("source_encoding_name"));
04233 }
04234
04235
04236
04237
04238
04239
04240
04241
04242
04243
04244
04245
04246
04247
04248
04249
04250
04251
04252
04253
04254
04255 static VALUE
04256 ecerr_source_encoding(VALUE self)
04257 {
04258 return rb_attr_get(self, rb_intern("source_encoding"));
04259 }
04260
04261
04262
04263
04264
04265
04266
04267 static VALUE
04268 ecerr_destination_encoding_name(VALUE self)
04269 {
04270 return rb_attr_get(self, rb_intern("destination_encoding_name"));
04271 }
04272
04273
04274
04275
04276
04277
04278
04279 static VALUE
04280 ecerr_destination_encoding(VALUE self)
04281 {
04282 return rb_attr_get(self, rb_intern("destination_encoding"));
04283 }
04284
04285
04286
04287
04288
04289
04290
04291
04292
04293
04294
04295
04296
04297
04298
04299
04300 static VALUE
04301 ecerr_error_char(VALUE self)
04302 {
04303 return rb_attr_get(self, rb_intern("error_char"));
04304 }
04305
04306
04307
04308
04309
04310
04311
04312
04313
04314
04315
04316
04317
04318
04319
04320
04321 static VALUE
04322 ecerr_error_bytes(VALUE self)
04323 {
04324 return rb_attr_get(self, rb_intern("error_bytes"));
04325 }
04326
04327
04328
04329
04330
04331
04332
04333 static VALUE
04334 ecerr_readagain_bytes(VALUE self)
04335 {
04336 return rb_attr_get(self, rb_intern("readagain_bytes"));
04337 }
04338
04339
04340
04341
04342
04343
04344
04345
04346
04347
04348
04349
04350
04351
04352
04353
04354
04355
04356
04357
04358
04359
04360
04361
04362
04363 static VALUE
04364 ecerr_incomplete_input(VALUE self)
04365 {
04366 return rb_attr_get(self, rb_intern("incomplete_input"));
04367 }
04368
04369
04370
04371
04372
04373
04374
04375
04376
04377
04378
04379
04380
04381
04382
04383
04384
04385
04386
04387
04388
04389
04390
04391 void
04392 Init_transcode(void)
04393 {
04394 rb_eUndefinedConversionError = rb_define_class_under(rb_cEncoding, "UndefinedConversionError", rb_eEncodingError);
04395 rb_eInvalidByteSequenceError = rb_define_class_under(rb_cEncoding, "InvalidByteSequenceError", rb_eEncodingError);
04396 rb_eConverterNotFoundError = rb_define_class_under(rb_cEncoding, "ConverterNotFoundError", rb_eEncodingError);
04397
04398 transcoder_table = st_init_strcasetable();
04399
04400 sym_invalid = ID2SYM(rb_intern("invalid"));
04401 sym_undef = ID2SYM(rb_intern("undef"));
04402 sym_replace = ID2SYM(rb_intern("replace"));
04403 sym_fallback = ID2SYM(rb_intern("fallback"));
04404 sym_aref = ID2SYM(rb_intern("[]"));
04405 sym_xml = ID2SYM(rb_intern("xml"));
04406 sym_text = ID2SYM(rb_intern("text"));
04407 sym_attr = ID2SYM(rb_intern("attr"));
04408
04409 sym_invalid_byte_sequence = ID2SYM(rb_intern("invalid_byte_sequence"));
04410 sym_undefined_conversion = ID2SYM(rb_intern("undefined_conversion"));
04411 sym_destination_buffer_full = ID2SYM(rb_intern("destination_buffer_full"));
04412 sym_source_buffer_empty = ID2SYM(rb_intern("source_buffer_empty"));
04413 sym_finished = ID2SYM(rb_intern("finished"));
04414 sym_after_output = ID2SYM(rb_intern("after_output"));
04415 sym_incomplete_input = ID2SYM(rb_intern("incomplete_input"));
04416 sym_universal_newline = ID2SYM(rb_intern("universal_newline"));
04417 sym_crlf_newline = ID2SYM(rb_intern("crlf_newline"));
04418 sym_cr_newline = ID2SYM(rb_intern("cr_newline"));
04419 sym_partial_input = ID2SYM(rb_intern("partial_input"));
04420
04421 #ifdef ENABLE_ECONV_NEWLINE_OPTION
04422 sym_newline = ID2SYM(rb_intern("newline"));
04423 sym_universal = ID2SYM(rb_intern("universal"));
04424 sym_crlf = ID2SYM(rb_intern("crlf"));
04425 sym_cr = ID2SYM(rb_intern("cr"));
04426 sym_lf = ID2SYM(rb_intern("lf"));
04427 #endif
04428
04429 rb_define_method(rb_cString, "encode", str_encode, -1);
04430 rb_define_method(rb_cString, "encode!", str_encode_bang, -1);
04431
04432 rb_cEncodingConverter = rb_define_class_under(rb_cEncoding, "Converter", rb_cData);
04433 rb_define_alloc_func(rb_cEncodingConverter, econv_s_allocate);
04434 rb_define_singleton_method(rb_cEncodingConverter, "asciicompat_encoding", econv_s_asciicompat_encoding, 1);
04435 rb_define_singleton_method(rb_cEncodingConverter, "search_convpath", econv_s_search_convpath, -1);
04436 rb_define_method(rb_cEncodingConverter, "initialize", econv_init, -1);
04437 rb_define_method(rb_cEncodingConverter, "inspect", econv_inspect, 0);
04438 rb_define_method(rb_cEncodingConverter, "convpath", econv_convpath, 0);
04439 rb_define_method(rb_cEncodingConverter, "source_encoding", econv_source_encoding, 0);
04440 rb_define_method(rb_cEncodingConverter, "destination_encoding", econv_destination_encoding, 0);
04441 rb_define_method(rb_cEncodingConverter, "primitive_convert", econv_primitive_convert, -1);
04442 rb_define_method(rb_cEncodingConverter, "convert", econv_convert, 1);
04443 rb_define_method(rb_cEncodingConverter, "finish", econv_finish, 0);
04444 rb_define_method(rb_cEncodingConverter, "primitive_errinfo", econv_primitive_errinfo, 0);
04445 rb_define_method(rb_cEncodingConverter, "insert_output", econv_insert_output, 1);
04446 rb_define_method(rb_cEncodingConverter, "putback", econv_putback, -1);
04447 rb_define_method(rb_cEncodingConverter, "last_error", econv_last_error, 0);
04448 rb_define_method(rb_cEncodingConverter, "replacement", econv_get_replacement, 0);
04449 rb_define_method(rb_cEncodingConverter, "replacement=", econv_set_replacement, 1);
04450 rb_define_method(rb_cEncodingConverter, "==", econv_equal, 1);
04451
04452
04453
04454
04455
04456 rb_define_const(rb_cEncodingConverter, "INVALID_MASK", INT2FIX(ECONV_INVALID_MASK));
04457
04458
04459
04460
04461
04462 rb_define_const(rb_cEncodingConverter, "INVALID_REPLACE", INT2FIX(ECONV_INVALID_REPLACE));
04463
04464
04465
04466
04467
04468
04469 rb_define_const(rb_cEncodingConverter, "UNDEF_MASK", INT2FIX(ECONV_UNDEF_MASK));
04470
04471
04472
04473
04474
04475 rb_define_const(rb_cEncodingConverter, "UNDEF_REPLACE", INT2FIX(ECONV_UNDEF_REPLACE));
04476
04477
04478
04479
04480
04481
04482
04483 rb_define_const(rb_cEncodingConverter, "UNDEF_HEX_CHARREF", INT2FIX(ECONV_UNDEF_HEX_CHARREF));
04484
04485
04486
04487
04488
04489
04490 rb_define_const(rb_cEncodingConverter, "PARTIAL_INPUT", INT2FIX(ECONV_PARTIAL_INPUT));
04491
04492
04493
04494
04495
04496
04497 rb_define_const(rb_cEncodingConverter, "AFTER_OUTPUT", INT2FIX(ECONV_AFTER_OUTPUT));
04498
04499
04500
04501
04502
04503 rb_define_const(rb_cEncodingConverter, "UNIVERSAL_NEWLINE_DECORATOR", INT2FIX(ECONV_UNIVERSAL_NEWLINE_DECORATOR));
04504
04505
04506
04507
04508
04509 rb_define_const(rb_cEncodingConverter, "CRLF_NEWLINE_DECORATOR", INT2FIX(ECONV_CRLF_NEWLINE_DECORATOR));
04510
04511
04512
04513
04514
04515 rb_define_const(rb_cEncodingConverter, "CR_NEWLINE_DECORATOR", INT2FIX(ECONV_CR_NEWLINE_DECORATOR));
04516
04517
04518
04519
04520
04521 rb_define_const(rb_cEncodingConverter, "XML_TEXT_DECORATOR", INT2FIX(ECONV_XML_TEXT_DECORATOR));
04522
04523
04524
04525
04526
04527 rb_define_const(rb_cEncodingConverter, "XML_ATTR_CONTENT_DECORATOR", INT2FIX(ECONV_XML_ATTR_CONTENT_DECORATOR));
04528
04529
04530
04531
04532
04533 rb_define_const(rb_cEncodingConverter, "XML_ATTR_QUOTE_DECORATOR", INT2FIX(ECONV_XML_ATTR_QUOTE_DECORATOR));
04534
04535 rb_define_method(rb_eUndefinedConversionError, "source_encoding_name", ecerr_source_encoding_name, 0);
04536 rb_define_method(rb_eUndefinedConversionError, "destination_encoding_name", ecerr_destination_encoding_name, 0);
04537 rb_define_method(rb_eUndefinedConversionError, "source_encoding", ecerr_source_encoding, 0);
04538 rb_define_method(rb_eUndefinedConversionError, "destination_encoding", ecerr_destination_encoding, 0);
04539 rb_define_method(rb_eUndefinedConversionError, "error_char", ecerr_error_char, 0);
04540
04541 rb_define_method(rb_eInvalidByteSequenceError, "source_encoding_name", ecerr_source_encoding_name, 0);
04542 rb_define_method(rb_eInvalidByteSequenceError, "destination_encoding_name", ecerr_destination_encoding_name, 0);
04543 rb_define_method(rb_eInvalidByteSequenceError, "source_encoding", ecerr_source_encoding, 0);
04544 rb_define_method(rb_eInvalidByteSequenceError, "destination_encoding", ecerr_destination_encoding, 0);
04545 rb_define_method(rb_eInvalidByteSequenceError, "error_bytes", ecerr_error_bytes, 0);
04546 rb_define_method(rb_eInvalidByteSequenceError, "readagain_bytes", ecerr_readagain_bytes, 0);
04547 rb_define_method(rb_eInvalidByteSequenceError, "incomplete_input?", ecerr_incomplete_input, 0);
04548
04549 Init_newline();
04550 }
04551