12#include "ruby/internal/config.h"
17#include "internal/array.h"
18#include "internal/inits.h"
19#include "internal/object.h"
20#include "internal/string.h"
21#include "internal/transcode.h"
22#include "internal/encoding.h"
26#include "transcode_data.h"
29#define ENABLE_ECONV_NEWLINE_OPTION 1
32static VALUE rb_eUndefinedConversionError;
33static VALUE rb_eInvalidByteSequenceError;
34static VALUE rb_eConverterNotFoundError;
36VALUE rb_cEncodingConverter;
38static ID id_destination_encoding;
39static ID id_destination_encoding_name;
40static ID id_error_bytes;
41static ID id_error_char;
42static ID id_incomplete_input;
43static ID id_readagain_bytes;
44static ID id_source_encoding;
45static ID id_source_encoding_name;
47static VALUE sym_invalid, sym_undef, sym_replace, sym_fallback;
48static VALUE sym_xml, sym_text, sym_attr;
49static VALUE sym_universal_newline;
50static VALUE sym_crlf_newline;
51static VALUE sym_cr_newline;
52static VALUE sym_lf_newline;
53#ifdef ENABLE_ECONV_NEWLINE_OPTION
54static VALUE sym_newline, sym_universal, sym_crlf, sym_cr, sym_lf;
56static VALUE sym_partial_input;
58static VALUE sym_invalid_byte_sequence;
59static VALUE sym_undefined_conversion;
60static VALUE sym_destination_buffer_full;
61static VALUE sym_source_buffer_empty;
62static VALUE sym_finished;
63static VALUE sym_after_output;
64static VALUE sym_incomplete_input;
67allocate_converted_string(
const char *sname,
const char *dname,
68 const unsigned char *str,
size_t len,
69 unsigned char *caller_dst_buf,
size_t caller_dst_bufsize,
80 unsigned int next_table;
82 unsigned char next_byte;
83 unsigned int output_index;
85 ssize_t recognized_len;
86 ssize_t readagain_len;
101 char ary[
sizeof(double) >
sizeof(
void*) ?
sizeof(double) :
sizeof(
void*)];
102 double dummy_for_alignment;
105#define TRANSCODING_READBUF(tc) \
106 ((tc)->transcoder->max_input <= (int)sizeof((tc)->readbuf.ary) ? \
107 (tc)->readbuf.ary : \
109#define TRANSCODING_WRITEBUF(tc) \
110 ((tc)->transcoder->max_output <= (int)sizeof((tc)->writebuf.ary) ? \
111 (tc)->writebuf.ary : \
113#define TRANSCODING_WRITEBUF_SIZE(tc) \
114 ((tc)->transcoder->max_output <= (int)sizeof((tc)->writebuf.ary) ? \
115 sizeof((tc)->writebuf.ary) : \
116 (size_t)(tc)->transcoder->max_output)
117#define TRANSCODING_STATE_EMBED_MAX ((int)sizeof(union rb_transcoding_state_t))
118#define TRANSCODING_STATE(tc) \
119 ((tc)->transcoder->state_size <= (int)sizeof((tc)->state) ? \
125 unsigned char *out_buf_start;
126 unsigned char *out_data_start;
127 unsigned char *out_data_end;
128 unsigned char *out_buf_end;
136 const char *source_encoding_name;
137 const char *destination_encoding_name;
139 const unsigned char *replacement_str;
140 size_t replacement_len;
141 const char *replacement_enc;
143 unsigned char *in_buf_start;
144 unsigned char *in_data_start;
145 unsigned char *in_data_end;
146 unsigned char *in_buf_end;
148 int replacement_allocated;
158 const char *source_encoding;
159 const char *destination_encoding;
160 const unsigned char *error_bytes_start;
161 size_t error_bytes_len;
162 size_t readagain_len;
167 rb_encoding *source_encoding;
168 rb_encoding *destination_encoding;
175#define DECORATOR_P(sname, dname) (*(sname) == '\0')
184static st_table *transcoder_table;
187free_inner_transcode_i(st_data_t key, st_data_t val, st_data_t arg)
194free_transcode_i(st_data_t key, st_data_t val, st_data_t arg)
196 st_foreach((
void *)val, free_inner_transcode_i, 0);
197 st_free_table((
void *)val);
202rb_free_transcoder_table(
void)
204 st_foreach(transcoder_table, free_transcode_i, 0);
205 st_free_table(transcoder_table);
209make_transcoder_entry(
const char *sname,
const char *dname)
215 if (!st_lookup(transcoder_table, (st_data_t)sname, &val)) {
216 val = (st_data_t)st_init_strcasetable();
217 st_add_direct(transcoder_table, (st_data_t)sname, val);
219 table2 = (st_table *)val;
220 if (!st_lookup(table2, (st_data_t)dname, &val)) {
222 entry->sname = sname;
223 entry->dname = dname;
225 entry->transcoder = NULL;
226 val = (st_data_t)entry;
227 st_add_direct(table2, (st_data_t)dname, val);
234get_transcoder_entry(
const char *sname,
const char *dname)
239 if (st_lookup(transcoder_table, (st_data_t)sname, &val)) {
240 table2 = (st_table *)val;
241 if (!st_lookup(table2, (st_data_t)dname, &val)) {
252 const char *
const sname =
tr->src_encoding;
253 const char *
const dname =
tr->dst_encoding;
258 entry = make_transcoder_entry(sname, dname);
259 if (entry->transcoder) {
260 rb_raise(rb_eArgError,
"transcoder from %s to %s has been already registered",
263 entry->transcoder =
tr;
268declare_transcoder(
const char *sname,
const char *dname,
const char *lib)
272 entry = make_transcoder_entry(sname, dname);
276static const char transcoder_lib_prefix[] =
"enc/trans/";
279rb_declare_transcoder(
const char *enc1,
const char *enc2,
const char *lib)
282 rb_raise(rb_eArgError,
"invalid library name - (null)");
284 declare_transcoder(enc1, enc2, lib);
287#define encoding_equal(enc1, enc2) (STRCASECMP((enc1), (enc2)) == 0)
292} search_path_queue_t;
296 search_path_queue_t *queue;
297 search_path_queue_t **queue_last_ptr;
298 const char *base_enc;
302transcode_search_path_i(st_data_t key, st_data_t val, st_data_t arg)
304 const char *dname = (
const char *)key;
306 search_path_queue_t *q;
308 if (st_lookup(bfs->visited, (st_data_t)dname, &val)) {
312 q =
ALLOC(search_path_queue_t);
315 *bfs->queue_last_ptr = q;
316 bfs->queue_last_ptr = &q->next;
318 st_add_direct(bfs->visited, (st_data_t)dname, (st_data_t)bfs->base_enc);
323transcode_search_path(
const char *sname,
const char *dname,
324 void (*callback)(
const char *sname,
const char *dname,
int depth,
void *arg),
328 search_path_queue_t *q;
335 if (encoding_equal(sname, dname))
338 q =
ALLOC(search_path_queue_t);
341 bfs.queue_last_ptr = &q->next;
344 bfs.visited = st_init_strcasetable();
345 st_add_direct(bfs.visited, (st_data_t)sname, (st_data_t)NULL);
352 bfs.queue_last_ptr = &bfs.queue;
355 lookup_res = st_lookup(transcoder_table, (st_data_t)q->enc, &val);
360 table2 = (st_table *)val;
362 if (st_lookup(table2, (st_data_t)dname, &val)) {
363 st_add_direct(bfs.visited, (st_data_t)dname, (st_data_t)q->enc);
369 bfs.base_enc = q->enc;
370 st_foreach(table2, transcode_search_path_i, (st_data_t)&bfs);
384 const char *enc = dname;
388 st_lookup(bfs.visited, (st_data_t)enc, &val);
392 enc = (
const char *)val;
397 st_lookup(bfs.visited, (st_data_t)enc, &val);
400 callback((
const char *)val, enc, --depth, arg);
401 enc = (
const char *)val;
405 st_free_table(bfs.visited);
410int rb_require_internal_silent(
VALUE fname);
415 ASSERT_vm_unlocking();
416 if (entry->transcoder)
417 return entry->transcoder;
420 const char *
const lib = entry->lib;
421 const size_t len = strlen(lib);
422 const size_t total_len =
sizeof(transcoder_lib_prefix) - 1 +
len;
424 char *
const path = RSTRING_PTR(fn);
426 memcpy(path, transcoder_lib_prefix,
sizeof(transcoder_lib_prefix) - 1);
427 memcpy(path +
sizeof(transcoder_lib_prefix) - 1, lib,
len);
430 rb_require_internal_silent(fn);
433 if (entry->transcoder)
434 return entry->transcoder;
440get_replacement_character(
const char *encname,
size_t *len_ret,
const char **repl_encname_ptr)
442 if (encoding_equal(encname,
"UTF-8")) {
444 *repl_encname_ptr =
"UTF-8";
445 return "\xEF\xBF\xBD";
449 *repl_encname_ptr =
"US-ASCII";
458static const unsigned char *
460 const unsigned char *in_start,
461 const unsigned char *inchar_start,
462 const unsigned char *in_p,
463 size_t *char_len_ptr)
465 const unsigned char *
ptr;
466 if (inchar_start - in_start < tc->recognized_len) {
467 MEMCPY(TRANSCODING_READBUF(tc) + tc->recognized_len,
468 inchar_start,
unsigned char, in_p - inchar_start);
469 ptr = TRANSCODING_READBUF(tc);
472 ptr = inchar_start - tc->recognized_len;
474 *char_len_ptr = tc->recognized_len + (in_p - inchar_start);
479transcode_restartable0(
const unsigned char **in_pos,
unsigned char **out_pos,
480 const unsigned char *in_stop,
unsigned char *out_stop,
485 int unitlen =
tr->input_unit_length;
486 ssize_t readagain_len = 0;
488 const unsigned char *inchar_start;
489 const unsigned char *in_p;
491 unsigned char *out_p;
493 in_p = inchar_start = *in_pos;
497#define SUSPEND(ret, num) \
499 tc->resume_position = (num); \
500 if (0 < in_p - inchar_start) \
501 MEMMOVE(TRANSCODING_READBUF(tc)+tc->recognized_len, \
502 inchar_start, unsigned char, in_p - inchar_start); \
505 tc->recognized_len += in_p - inchar_start; \
506 if (readagain_len) { \
507 tc->recognized_len -= readagain_len; \
508 tc->readagain_len = readagain_len; \
511 resume_label ## num:; \
513#define SUSPEND_OBUF(num) \
515 while (out_stop - out_p < 1) { SUSPEND(econv_destination_buffer_full, num); } \
518#define SUSPEND_AFTER_OUTPUT(num) \
519 if ((opt & ECONV_AFTER_OUTPUT) && *out_pos != out_p) { \
520 SUSPEND(econv_after_output, num); \
523#define next_table (tc->next_table)
524#define next_info (tc->next_info)
525#define next_byte (tc->next_byte)
526#define writebuf_len (tc->writebuf_len)
527#define writebuf_off (tc->writebuf_off)
529 switch (tc->resume_position) {
531 case 1:
goto resume_label1;
532 case 2:
goto resume_label2;
533 case 3:
goto resume_label3;
534 case 4:
goto resume_label4;
535 case 5:
goto resume_label5;
536 case 6:
goto resume_label6;
537 case 7:
goto resume_label7;
538 case 8:
goto resume_label8;
539 case 9:
goto resume_label9;
540 case 10:
goto resume_label10;
541 case 11:
goto resume_label11;
542 case 12:
goto resume_label12;
543 case 13:
goto resume_label13;
544 case 14:
goto resume_label14;
545 case 15:
goto resume_label15;
546 case 16:
goto resume_label16;
547 case 17:
goto resume_label17;
548 case 18:
goto resume_label18;
549 case 19:
goto resume_label19;
550 case 20:
goto resume_label20;
551 case 21:
goto resume_label21;
552 case 22:
goto resume_label22;
553 case 23:
goto resume_label23;
554 case 24:
goto resume_label24;
555 case 25:
goto resume_label25;
556 case 26:
goto resume_label26;
557 case 27:
goto resume_label27;
558 case 28:
goto resume_label28;
559 case 29:
goto resume_label29;
560 case 30:
goto resume_label30;
561 case 31:
goto resume_label31;
562 case 32:
goto resume_label32;
563 case 33:
goto resume_label33;
564 case 34:
goto resume_label34;
569 tc->recognized_len = 0;
570 next_table =
tr->conv_tree_start;
572 SUSPEND_AFTER_OUTPUT(24);
574 if (in_stop <= in_p) {
581#define BYTE_ADDR(index) (tr->byte_array + (index))
582#define WORD_ADDR(index) (tr->word_array + INFO2WORDINDEX(index))
583#define BL_BASE BYTE_ADDR(BYTE_LOOKUP_BASE(WORD_ADDR(next_table)))
584#define BL_INFO WORD_ADDR(BYTE_LOOKUP_INFO(WORD_ADDR(next_table)))
585#define BL_MIN_BYTE (BL_BASE[0])
586#define BL_MAX_BYTE (BL_BASE[1])
587#define BL_OFFSET(byte) (BL_BASE[2+(byte)-BL_MIN_BYTE])
588#define BL_ACTION(byte) (BL_INFO[BL_OFFSET((byte))])
590 next_byte = (
unsigned char)*in_p++;
592 if (next_byte < BL_MIN_BYTE || BL_MAX_BYTE < next_byte)
595 next_info = (
VALUE)BL_ACTION(next_byte);
598 switch (next_info & 0x1F) {
601 const unsigned char *p = inchar_start;
604 TRANSCODING_WRITEBUF(tc)[writebuf_off++] = (
unsigned char)*p++;
606 writebuf_len = writebuf_off;
608 while (writebuf_off < writebuf_len) {
610 *out_p++ = TRANSCODING_WRITEBUF(tc)[writebuf_off++];
614 case 0x00:
case 0x04:
case 0x08:
case 0x0C:
615 case 0x10:
case 0x14:
case 0x18:
case 0x1C:
616 SUSPEND_AFTER_OUTPUT(25);
617 while (in_p >= in_stop) {
622 next_byte = (
unsigned char)*in_p++;
623 next_table = (
unsigned int)next_info;
628 SUSPEND_OBUF(9); *out_p++ = getBT1(next_info);
631 SUSPEND_OBUF(10); *out_p++ = getBT1(next_info);
632 SUSPEND_OBUF(21); *out_p++ = getBT2(next_info);
635 SUSPEND_OBUF(11); *out_p++ = getBT1(next_info);
636 SUSPEND_OBUF(15); *out_p++ = getBT2(next_info);
637 SUSPEND_OBUF(16); *out_p++ = getBT3(next_info);
640 SUSPEND_OBUF(12); *out_p++ = getBT0(next_info);
641 SUSPEND_OBUF(17); *out_p++ = getBT1(next_info);
642 SUSPEND_OBUF(18); *out_p++ = getBT2(next_info);
643 SUSPEND_OBUF(19); *out_p++ = getBT3(next_info);
646 SUSPEND_OBUF(29); *out_p++ = getGB4bt0(next_info);
647 SUSPEND_OBUF(30); *out_p++ = getGB4bt1(next_info);
648 SUSPEND_OBUF(31); *out_p++ = getGB4bt2(next_info);
649 SUSPEND_OBUF(32); *out_p++ = getGB4bt3(next_info);
652 tc->output_index = 0;
653 while (tc->output_index < STR1_LENGTH(BYTE_ADDR(STR1_BYTEINDEX(next_info)))) {
654 SUSPEND_OBUF(28); *out_p++ = BYTE_ADDR(STR1_BYTEINDEX(next_info))[1+tc->output_index];
659 next_info = (
VALUE)(*
tr->func_ii)(TRANSCODING_STATE(tc), next_info);
663 const unsigned char *char_start;
665 char_start = transcode_char_start(tc, *in_pos, inchar_start, in_p, &char_len);
666 next_info = (
VALUE)(*
tr->func_si)(TRANSCODING_STATE(tc), char_start, (size_t)char_len);
671 if (
tr->max_output <= out_stop - out_p)
672 out_p +=
tr->func_io(TRANSCODING_STATE(tc),
673 next_info, out_p, out_stop - out_p);
675 writebuf_len =
tr->func_io(TRANSCODING_STATE(tc),
677 TRANSCODING_WRITEBUF(tc), TRANSCODING_WRITEBUF_SIZE(tc));
679 while (writebuf_off < writebuf_len) {
681 *out_p++ = TRANSCODING_WRITEBUF(tc)[writebuf_off++];
687 const unsigned char *char_start;
690 if (
tr->max_output <= out_stop - out_p) {
691 char_start = transcode_char_start(tc, *in_pos, inchar_start, in_p, &char_len);
692 out_p +=
tr->func_so(TRANSCODING_STATE(tc),
693 char_start, (
size_t)char_len,
694 out_p, out_stop - out_p);
697 char_start = transcode_char_start(tc, *in_pos, inchar_start, in_p, &char_len);
698 writebuf_len =
tr->func_so(TRANSCODING_STATE(tc),
699 char_start, (
size_t)char_len,
700 TRANSCODING_WRITEBUF(tc), TRANSCODING_WRITEBUF_SIZE(tc));
702 while (writebuf_off < writebuf_len) {
704 *out_p++ = TRANSCODING_WRITEBUF(tc)[writebuf_off++];
711 const unsigned char *char_start;
714 if (
tr->max_output <= out_stop - out_p) {
715 char_start = transcode_char_start(tc, *in_pos, inchar_start, in_p, &char_len);
716 out_p +=
tr->func_sio(TRANSCODING_STATE(tc),
717 char_start, (
size_t)char_len, next_info,
718 out_p, out_stop - out_p);
721 char_start = transcode_char_start(tc, *in_pos, inchar_start, in_p, &char_len);
722 writebuf_len =
tr->func_sio(TRANSCODING_STATE(tc),
723 char_start, (
size_t)char_len, next_info,
724 TRANSCODING_WRITEBUF(tc), TRANSCODING_WRITEBUF_SIZE(tc));
726 while (writebuf_off < writebuf_len) {
728 *out_p++ = TRANSCODING_WRITEBUF(tc)[writebuf_off++];
734 if (tc->recognized_len + (in_p - inchar_start) <= unitlen) {
735 if (tc->recognized_len + (in_p - inchar_start) < unitlen)
736 SUSPEND_AFTER_OUTPUT(26);
737 while ((opt &
ECONV_PARTIAL_INPUT) && tc->recognized_len + (in_stop - inchar_start) < unitlen) {
741 if (tc->recognized_len + (in_stop - inchar_start) <= unitlen) {
745 in_p = inchar_start + (unitlen - tc->recognized_len);
751 invalid_len = tc->recognized_len + (in_p - inchar_start);
752 discard_len = ((invalid_len - 1) / unitlen) * unitlen;
753 readagain_len = invalid_len - discard_len;
777 if (
tr->finish_func) {
779 if (
tr->max_output <= out_stop - out_p) {
780 out_p +=
tr->finish_func(TRANSCODING_STATE(tc),
781 out_p, out_stop - out_p);
784 writebuf_len =
tr->finish_func(TRANSCODING_STATE(tc),
785 TRANSCODING_WRITEBUF(tc), TRANSCODING_WRITEBUF_SIZE(tc));
787 while (writebuf_off < writebuf_len) {
789 *out_p++ = TRANSCODING_WRITEBUF(tc)[writebuf_off++];
804transcode_restartable(
const unsigned char **in_pos,
unsigned char **out_pos,
805 const unsigned char *in_stop,
unsigned char *out_stop,
809 if (tc->readagain_len) {
810 unsigned char *readagain_buf =
ALLOCA_N(
unsigned char, tc->readagain_len);
811 const unsigned char *readagain_pos = readagain_buf;
812 const unsigned char *readagain_stop = readagain_buf + tc->readagain_len;
815 MEMCPY(readagain_buf, TRANSCODING_READBUF(tc) + tc->recognized_len,
816 unsigned char, tc->readagain_len);
817 tc->readagain_len = 0;
818 res = transcode_restartable0(&readagain_pos, out_pos, readagain_stop, out_stop, tc, opt|
ECONV_PARTIAL_INPUT);
820 MEMCPY(TRANSCODING_READBUF(tc) + tc->recognized_len + tc->readagain_len,
821 readagain_pos,
unsigned char, readagain_stop - readagain_pos);
822 tc->readagain_len += readagain_stop - readagain_pos;
826 return transcode_restartable0(in_pos, out_pos, in_stop, out_stop, tc, opt);
837 if (TRANSCODING_STATE_EMBED_MAX < tr->state_size)
839 if (
tr->state_init_func) {
840 (
tr->state_init_func)(TRANSCODING_STATE(tc));
842 tc->resume_position = 0;
843 tc->recognized_len = 0;
844 tc->readagain_len = 0;
845 tc->writebuf_len = 0;
846 tc->writebuf_off = 0;
847 if ((
int)
sizeof(tc->readbuf.ary) <
tr->max_input) {
848 tc->readbuf.ptr =
xmalloc(
tr->max_input);
850 if ((
int)
sizeof(tc->writebuf.ary) <
tr->max_output) {
851 tc->writebuf.ptr =
xmalloc(
tr->max_output);
858 const unsigned char **input_ptr,
const unsigned char *input_stop,
859 unsigned char **output_ptr,
unsigned char *output_stop,
862 return transcode_restartable(
863 input_ptr, output_ptr,
864 input_stop, output_stop,
872 if (
tr->state_fini_func) {
873 (
tr->state_fini_func)(TRANSCODING_STATE(tc));
875 if (TRANSCODING_STATE_EMBED_MAX < tr->state_size)
876 xfree(tc->state.ptr);
877 if ((
int)
sizeof(tc->readbuf.ary) <
tr->max_input)
878 xfree(tc->readbuf.ptr);
879 if ((
int)
sizeof(tc->writebuf.ary) <
tr->max_output)
880 xfree(tc->writebuf.ptr);
890 if (TRANSCODING_STATE_EMBED_MAX < tr->state_size) {
891 size +=
tr->state_size;
893 if ((
int)
sizeof(tc->readbuf.ary) <
tr->max_input) {
894 size +=
tr->max_input;
896 if ((
int)
sizeof(tc->writebuf.ary) <
tr->max_output) {
897 size +=
tr->max_output;
903rb_econv_alloc(
int n_hint)
912 ec->source_encoding_name = NULL;
913 ec->destination_encoding_name = NULL;
915 ec->replacement_str = NULL;
916 ec->replacement_len = 0;
917 ec->replacement_enc = NULL;
918 ec->replacement_allocated = 0;
919 ec->in_buf_start = NULL;
920 ec->in_data_start = NULL;
921 ec->in_data_end = NULL;
922 ec->in_buf_end = NULL;
923 ec->num_allocated = n_hint;
926 ec->num_finished = 0;
929 ec->last_error.error_tc = NULL;
930 ec->last_error.source_encoding = NULL;
931 ec->last_error.destination_encoding = NULL;
932 ec->last_error.error_bytes_start = NULL;
933 ec->last_error.error_bytes_len = 0;
934 ec->last_error.readagain_len = 0;
935 ec->source_encoding = NULL;
936 ec->destination_encoding = NULL;
947 if (ec->num_trans == ec->num_allocated) {
948 n = ec->num_allocated * 2;
950 ec->num_allocated = n;
957 ec->elems[i].tc = rb_transcoding_open_by_transcoder(
tr, 0);
958 ec->elems[i].out_buf_start = p;
959 ec->elems[i].out_buf_end = p + bufsize;
960 ec->elems[i].out_data_start = p;
961 ec->elems[i].out_data_end = p;
966 if (!DECORATOR_P(
tr->src_encoding,
tr->dst_encoding))
967 for (j = ec->num_trans-1; i <= j; j--) {
970 if (!DECORATOR_P(tr2->src_encoding, tr2->dst_encoding)) {
985 for (i = 0; i < n; i++) {
987 tr = load_transcoder_entry(entries[i]);
992 ec = rb_econv_alloc(n);
994 for (i = 0; i < n; i++) {
996 ret = rb_econv_add_transcoder_at(ec,
tr, ec->num_trans);
1012trans_open_i(
const char *sname,
const char *dname,
int depth,
void *arg)
1016 if (!toarg->entries) {
1019 toarg->entries[depth] = get_transcoder_entry(sname, dname);
1023rb_econv_open0(
const char *sname,
const char *dname,
int ecflags)
1030 if (*sname) rb_enc_find_index(sname);
1031 if (*dname) rb_enc_find_index(dname);
1033 if (*sname ==
'\0' && *dname ==
'\0') {
1040 toarg.entries = NULL;
1041 toarg.num_additional = 0;
1042 num_trans = transcode_search_path(sname, dname, trans_open_i, (
void *)&toarg);
1043 entries = toarg.entries;
1044 if (num_trans < 0) {
1048 sname = entries[0]->sname;
1049 dname = entries[num_trans-1]->dname;
1052 ec = rb_econv_open_by_transcoder_entries(num_trans, entries);
1057 ec->flags = ecflags;
1058 ec->source_encoding_name = sname;
1059 ec->destination_encoding_name = dname;
1064#define MAX_ECFLAGS_DECORATORS 32
1067decorator_names(
int ecflags,
const char **decorators_ret)
1089 decorators_ret[num_decorators++] =
"xml_text_escape";
1091 decorators_ret[num_decorators++] =
"xml_attr_content_escape";
1093 decorators_ret[num_decorators++] =
"xml_attr_quote";
1096 decorators_ret[num_decorators++] =
"crlf_newline";
1098 decorators_ret[num_decorators++] =
"cr_newline";
1100 decorators_ret[num_decorators++] =
"lf_newline";
1102 decorators_ret[num_decorators++] =
"universal_newline";
1104 return num_decorators;
1112 const char *decorators[MAX_ECFLAGS_DECORATORS];
1115 num_decorators = decorator_names(ecflags, decorators);
1116 if (num_decorators == -1)
1121 for (i = 0; i < num_decorators; i++) {
1138 const unsigned char **input_ptr,
const unsigned char *input_stop,
1139 unsigned char **output_ptr,
unsigned char *output_stop,
1146 const unsigned char **ipp, *is, *iold;
1147 unsigned char **opp, *os, *oold;
1153 for (i = start; i < ec->num_trans; i++) {
1162 ipp = (
const unsigned char **)&prev_te->out_data_start;
1163 is = prev_te->out_data_end;
1166 if (i == ec->num_trans-1) {
1171 if (te->out_buf_start != te->out_data_start) {
1172 ssize_t
len = te->out_data_end - te->out_data_start;
1173 ssize_t
off = te->out_data_start - te->out_buf_start;
1174 MEMMOVE(te->out_buf_start, te->out_data_start,
unsigned char,
len);
1175 te->out_data_start = te->out_buf_start;
1176 te->out_data_end -=
off;
1178 opp = &te->out_data_end;
1179 os = te->out_buf_end;
1183 if (ec->num_finished != i)
1193 te->last_result = res = rb_transcoding_convert(te->tc, ipp, is, opp, os, f);
1194 if (iold != *ipp || oold != *opp)
1209 ec->num_finished = i+1;
1219 const unsigned char **input_ptr,
const unsigned char *input_stop,
1220 unsigned char **output_ptr,
unsigned char *output_stop,
1222 int *result_position_ptr)
1225 int needreport_index;
1228 unsigned char empty_buf;
1229 unsigned char *empty_ptr = &empty_buf;
1232 input_ptr = (
const unsigned char **)&empty_ptr;
1233 input_stop = empty_ptr;
1237 output_ptr = &empty_ptr;
1238 output_stop = empty_ptr;
1244 for (i = ec->num_trans-1; 0 <= i; i--) {
1245 switch (ec->elems[i].last_result) {
1252 goto found_needreport;
1259 rb_bug(
"unexpected transcode last result");
1269 res = rb_trans_conv(ec, NULL, NULL, output_ptr, output_stop,
1271 result_position_ptr);
1283 needreport_index = trans_sweep(ec, input_ptr, input_stop, output_ptr, output_stop, flags, sweep_start);
1284 sweep_start = needreport_index + 1;
1285 }
while (needreport_index != -1 && needreport_index != ec->num_trans-1);
1287 for (i = ec->num_trans-1; 0 <= i; i--) {
1296 if (result_position_ptr)
1297 *result_position_ptr = i;
1301 if (result_position_ptr)
1302 *result_position_ptr = -1;
1308 const unsigned char **input_ptr,
const unsigned char *input_stop,
1309 unsigned char **output_ptr,
unsigned char *output_stop,
1313 int result_position;
1316 memset(&ec->last_error, 0,
sizeof(ec->last_error));
1318 if (ec->num_trans == 0) {
1320 if (ec->in_buf_start && ec->in_data_start != ec->in_data_end) {
1321 if (output_stop - *output_ptr < ec->in_data_end - ec->in_data_start) {
1322 len = output_stop - *output_ptr;
1323 memcpy(*output_ptr, ec->in_data_start,
len);
1324 *output_ptr = output_stop;
1325 ec->in_data_start +=
len;
1329 len = ec->in_data_end - ec->in_data_start;
1330 memcpy(*output_ptr, ec->in_data_start,
len);
1332 ec->in_data_start = ec->in_data_end = ec->in_buf_start;
1338 if (output_stop - *output_ptr < input_stop - *input_ptr) {
1339 len = output_stop - *output_ptr;
1342 len = input_stop - *input_ptr;
1345 *(*output_ptr)++ = *(*input_ptr)++;
1349 memcpy(*output_ptr, *input_ptr,
len);
1352 if (*input_ptr != input_stop)
1361 if (ec->elems[ec->num_trans-1].out_data_start) {
1362 unsigned char *data_start = ec->elems[ec->num_trans-1].out_data_start;
1363 unsigned char *data_end = ec->elems[ec->num_trans-1].out_data_end;
1364 if (data_start != data_end) {
1366 if (output_stop - *output_ptr < data_end - data_start) {
1367 len = output_stop - *output_ptr;
1368 memcpy(*output_ptr, data_start,
len);
1369 *output_ptr = output_stop;
1370 ec->elems[ec->num_trans-1].out_data_start +=
len;
1374 len = data_end - data_start;
1375 memcpy(*output_ptr, data_start,
len);
1377 ec->elems[ec->num_trans-1].out_data_start =
1378 ec->elems[ec->num_trans-1].out_data_end =
1379 ec->elems[ec->num_trans-1].out_buf_start;
1384 if (ec->in_buf_start &&
1385 ec->in_data_start != ec->in_data_end) {
1386 res = rb_trans_conv(ec, (
const unsigned char **)&ec->in_data_start, ec->in_data_end, output_ptr, output_stop,
1394 *input_ptr != input_stop) {
1395 input_stop = *input_ptr;
1396 res = rb_trans_conv(ec, input_ptr, input_stop, output_ptr, output_stop, flags, &result_position);
1401 ec->num_trans == 1) {
1402 res = rb_trans_conv(ec, input_ptr, input_stop, output_ptr, output_stop, flags, &result_position);
1407 res = rb_trans_conv(ec, input_ptr, input_stop, output_ptr, output_stop, flags, &result_position);
1412 ec->last_error.result = res;
1417 ec->last_error.error_tc = error_tc;
1418 ec->last_error.source_encoding = error_tc->transcoder->src_encoding;
1419 ec->last_error.destination_encoding = error_tc->transcoder->dst_encoding;
1420 ec->last_error.error_bytes_start = TRANSCODING_READBUF(error_tc);
1421 ec->last_error.error_bytes_len = error_tc->recognized_len;
1422 ec->last_error.readagain_len = error_tc->readagain_len;
1428static int output_replacement_character(
rb_econv_t *ec);
1434 unsigned char utfbuf[1024];
1435 const unsigned char *utf;
1437 int utf_allocated = 0;
1438 char charef_buf[16];
1439 const unsigned char *p;
1441 if (encoding_equal(ec->last_error.source_encoding,
"UTF-32BE")) {
1442 utf = ec->last_error.error_bytes_start;
1443 utf_len = ec->last_error.error_bytes_len;
1446 utf = allocate_converted_string(ec->last_error.source_encoding,
"UTF-32BE",
1447 ec->last_error.error_bytes_start, ec->last_error.error_bytes_len,
1448 utfbuf,
sizeof(utfbuf),
1452 if (utf != utfbuf && utf != ec->last_error.error_bytes_start)
1456 if (utf_len % 4 != 0)
1460 while (4 <= utf_len) {
1466 snprintf(charef_buf,
sizeof(charef_buf),
"&#x%X;", u);
1488 const unsigned char **input_ptr,
const unsigned char *input_stop,
1489 unsigned char **output_ptr,
unsigned char *output_stop,
1494 unsigned char empty_buf;
1495 unsigned char *empty_ptr = &empty_buf;
1500 input_ptr = (
const unsigned char **)&empty_ptr;
1501 input_stop = empty_ptr;
1505 output_ptr = &empty_ptr;
1506 output_stop = empty_ptr;
1510 ret = rb_econv_convert0(ec, input_ptr, input_stop, output_ptr, output_stop, flags);
1518 if (output_replacement_character(ec) == 0)
1529 if (output_replacement_character(ec) == 0)
1534 if (output_hex_charref(ec) == 0)
1552 tr = tc->transcoder;
1554 if (
tr->asciicompat_type == asciicompat_encoder)
1555 return tr->src_encoding;
1556 return tr->dst_encoding;
1559static unsigned char *
1560allocate_converted_string(
const char *sname,
const char *dname,
1561 const unsigned char *str,
size_t len,
1562 unsigned char *caller_dst_buf,
size_t caller_dst_bufsize,
1563 size_t *dst_len_ptr)
1565 unsigned char *dst_str;
1572 const unsigned char *sp;
1576 dst_bufsize = caller_dst_bufsize;
1586 dst_str = caller_dst_buf;
1588 dst_str =
xmalloc(dst_bufsize);
1591 dp = dst_str+dst_len;
1593 dst_len = dp - dst_str;
1595 if (SIZE_MAX/2 < dst_bufsize) {
1599 if (dst_str == caller_dst_buf) {
1602 memcpy(tmp, dst_str, dst_bufsize/2);
1606 dst_str =
xrealloc(dst_str, dst_bufsize);
1608 dp = dst_str+dst_len;
1610 dst_len = dp - dst_str;
1616 *dst_len_ptr = dst_len;
1620 if (dst_str != caller_dst_buf)
1629 const unsigned char *str,
size_t len,
const char *str_encoding)
1632 unsigned char insert_buf[4096];
1633 const unsigned char *insert_str = NULL;
1636 int last_trans_index;
1639 unsigned char **buf_start_p;
1640 unsigned char **data_start_p;
1641 unsigned char **data_end_p;
1642 unsigned char **buf_end_p;
1651 if (encoding_equal(insert_encoding, str_encoding)) {
1656 insert_str = allocate_converted_string(str_encoding, insert_encoding,
1657 str,
len, insert_buf,
sizeof(insert_buf), &insert_len);
1658 if (insert_str == NULL)
1664 last_trans_index = ec->num_trans-1;
1665 if (ec->num_trans == 0) {
1667 buf_start_p = &ec->in_buf_start;
1668 data_start_p = &ec->in_data_start;
1669 data_end_p = &ec->in_data_end;
1670 buf_end_p = &ec->in_buf_end;
1672 else if (ec->elems[last_trans_index].tc->transcoder->asciicompat_type == asciicompat_encoder) {
1673 tc = ec->elems[last_trans_index].tc;
1674 need += tc->readagain_len;
1675 if (need < insert_len)
1677 if (last_trans_index == 0) {
1678 buf_start_p = &ec->in_buf_start;
1679 data_start_p = &ec->in_data_start;
1680 data_end_p = &ec->in_data_end;
1681 buf_end_p = &ec->in_buf_end;
1685 buf_start_p = &ee->out_buf_start;
1686 data_start_p = &ee->out_data_start;
1687 data_end_p = &ee->out_data_end;
1688 buf_end_p = &ee->out_buf_end;
1693 buf_start_p = &ee->out_buf_start;
1694 data_start_p = &ee->out_data_start;
1695 data_end_p = &ee->out_data_end;
1696 buf_end_p = &ee->out_buf_end;
1697 tc = ec->elems[last_trans_index].tc;
1700 if (*buf_start_p == NULL) {
1701 unsigned char *buf =
xmalloc(need);
1703 *data_start_p = buf;
1705 *buf_end_p = buf+need;
1707 else if ((
size_t)(*buf_end_p - *data_end_p) < need) {
1708 MEMMOVE(*buf_start_p, *data_start_p,
unsigned char, *data_end_p - *data_start_p);
1709 *data_end_p = *buf_start_p + (*data_end_p - *data_start_p);
1710 *data_start_p = *buf_start_p;
1711 if ((
size_t)(*buf_end_p - *data_end_p) < need) {
1713 size_t s = (*data_end_p - *buf_start_p) + need;
1717 *data_start_p = buf;
1718 *data_end_p = buf + (*data_end_p - *buf_start_p);
1720 *buf_end_p = buf + s;
1724 memcpy(*data_end_p, insert_str, insert_len);
1725 *data_end_p += insert_len;
1726 if (tc && tc->transcoder->asciicompat_type == asciicompat_encoder) {
1727 memcpy(*data_end_p, TRANSCODING_READBUF(tc)+tc->recognized_len, tc->readagain_len);
1728 *data_end_p += tc->readagain_len;
1729 tc->readagain_len = 0;
1732 if (insert_str != str && insert_str != insert_buf)
1733 xfree((
void*)insert_str);
1737 if (insert_str != str && insert_str != insert_buf)
1738 xfree((
void*)insert_str);
1747 if (ec->replacement_allocated) {
1748 xfree((
void *)ec->replacement_str);
1750 for (i = 0; i < ec->num_trans; i++) {
1751 rb_transcoding_close(ec->elems[i].tc);
1752 xfree(ec->elems[i].out_buf_start);
1754 xfree(ec->in_buf_start);
1765 if (ec->replacement_allocated) {
1766 size += ec->replacement_len;
1768 for (i = 0; i < ec->num_trans; i++) {
1769 size += rb_transcoding_memsize(ec->elems[i].tc);
1771 if (ec->elems[i].out_buf_start) {
1772 size += ec->elems[i].out_buf_end - ec->elems[i].out_buf_start;
1775 size += ec->in_buf_end - ec->in_buf_start;
1784 if (ec->num_trans == 0)
1786#if SIZEOF_SIZE_T > SIZEOF_INT
1787 if (ec->elems[0].tc->readagain_len > INT_MAX)
return INT_MAX;
1789 return (
int)ec->elems[0].tc->readagain_len;
1796 if (ec->num_trans == 0 || n == 0)
1798 tc = ec->elems[0].tc;
1799 memcpy(p, TRANSCODING_READBUF(tc) + tc->recognized_len + tc->readagain_len - n, n);
1800 tc->readagain_len -= n;
1804 const char *ascii_compat_name;
1805 const char *ascii_incompat_name;
1809asciicompat_encoding_i(st_data_t key, st_data_t val, st_data_t arg)
1815 if (DECORATOR_P(entry->sname, entry->dname))
1817 tr = load_transcoder_entry(entry);
1818 if (
tr &&
tr->asciicompat_type == asciicompat_decoder) {
1819 data->ascii_compat_name =
tr->dst_encoding;
1833 RB_VM_LOCK_ENTER_LEV(&lev);
1835 if (st_lookup(transcoder_table, (st_data_t)ascii_incompat_name, &v)) {
1836 table2 = (st_table *)v;
1844 if (table2->num_entries == 1) {
1845 data.ascii_incompat_name = ascii_incompat_name;
1846 data.ascii_compat_name = NULL;
1847 if (rb_multi_ractor_p()) {
1852 st_table *dup_table2 = st_copy(table2);
1853 RB_VM_LOCK_LEAVE_LEV(&lev);
1854 st_foreach(dup_table2, asciicompat_encoding_i, (st_data_t)&data);
1855 st_free_table(dup_table2);
1856 RB_VM_LOCK_ENTER_LEV(&lev);
1859 st_foreach(table2, asciicompat_encoding_i, (st_data_t)&data);
1865 RB_VM_LOCK_LEAVE_LEV(&lev);
1867 return data.ascii_compat_name;
1879 unsigned const char *sp, *se;
1880 unsigned char *ds, *dp, *de;
1884 rb_encoding *dst_enc = ec->destination_encoding;
1889 rb_enc_associate(dst, dst_enc);
1894 dst_enc = rb_enc_get(dst);
1899 max_output = ec->last_tc->transcoder->max_output;
1905 long dlen = RSTRING_LEN(dst);
1907 unsigned long new_capa = (
unsigned long)dlen +
len + max_output;
1908 if (LONG_MAX < new_capa)
1909 rb_raise(rb_eArgError,
"too long string");
1912 sp = (
const unsigned char *)ss;
1914 ds = (
unsigned char *)RSTRING_PTR(dst);
1918 switch (coderange) {
1921 cr = (int)coderange;
1930 len -= (
const char *)sp - ss;
1931 ss = (
const char *)sp;
1967rb_econv_add_converter(
rb_econv_t *ec,
const char *sname,
const char *dname,
int n)
1972 if (ec->started != 0)
1975 entry = get_transcoder_entry(sname, dname);
1977 tr = load_transcoder_entry(entry);
1980 return tr ? rb_econv_add_transcoder_at(ec,
tr, n) : -1;
1984rb_econv_decorate_at(
rb_econv_t *ec,
const char *decorator_name,
int n)
1986 return rb_econv_add_converter(ec,
"", decorator_name, n);
1994 if (ec->num_trans == 0)
1995 return rb_econv_decorate_at(ec, decorator_name, 0);
1997 tr = ec->elems[0].tc->transcoder;
1999 if (!DECORATOR_P(
tr->src_encoding,
tr->dst_encoding) &&
2000 tr->asciicompat_type == asciicompat_decoder)
2001 return rb_econv_decorate_at(ec, decorator_name, 1);
2003 return rb_econv_decorate_at(ec, decorator_name, 0);
2011 if (ec->num_trans == 0)
2012 return rb_econv_decorate_at(ec, decorator_name, 0);
2014 tr = ec->elems[ec->num_trans-1].tc->transcoder;
2016 if (!DECORATOR_P(
tr->src_encoding,
tr->dst_encoding) &&
2017 tr->asciicompat_type == asciicompat_encoder)
2018 return rb_econv_decorate_at(ec, decorator_name, ec->num_trans-1);
2020 return rb_econv_decorate_at(ec, decorator_name, ec->num_trans);
2026 const char *dname = 0;
2030 dname =
"universal_newline";
2033 dname =
"crlf_newline";
2036 dname =
"cr_newline";
2039 dname =
"lf_newline";
2044 const rb_transcoder *transcoder = get_transcoder_entry(
"", dname)->transcoder;
2045 int num_trans = ec->num_trans;
2048 for (i=0; i < num_trans; i++) {
2049 if (transcoder == ec->elems[i].tc->transcoder) {
2050 rb_transcoding_close(ec->elems[i].tc);
2051 xfree(ec->elems[i].out_buf_start);
2055 ec->elems[j++] = ec->elems[i];
2063econv_description(
const char *sname,
const char *dname,
int ecflags,
VALUE mesg)
2065 int has_description = 0;
2070 if (*sname !=
'\0' || *dname !=
'\0') {
2073 else if (*dname ==
'\0')
2076 rb_str_catf(mesg,
"%s to %s", sname, dname);
2077 has_description = 1;
2084 const char *pre =
"";
2085 if (has_description)
2115 has_description = 1;
2117 if (!has_description) {
2129 econv_description(sname, dname, ecflags, mesg);
2131 exc =
rb_exc_new3(rb_eConverterNotFoundError, mesg);
2141 const char *err = (
const char *)ec->last_error.error_bytes_start;
2142 size_t error_len = ec->last_error.error_bytes_len;
2145 size_t readagain_len = ec->last_error.readagain_len;
2149 mesg = rb_sprintf(
"incomplete %s on %s",
2151 ec->last_error.source_encoding);
2153 else if (readagain_len) {
2154 bytes2 =
rb_str_new(err+error_len, readagain_len);
2156 mesg = rb_sprintf(
"%s followed by %s on %s",
2159 ec->last_error.source_encoding);
2162 mesg = rb_sprintf(
"%s on %s",
2164 ec->last_error.source_encoding);
2167 exc =
rb_exc_new3(rb_eInvalidByteSequenceError, mesg);
2174 VALUE bytes =
rb_str_new((
const char *)ec->last_error.error_bytes_start,
2175 ec->last_error.error_bytes_len);
2178 if (strcmp(ec->last_error.source_encoding,
"UTF-8") == 0) {
2179 rb_encoding *utf8 = rb_utf8_encoding();
2180 const char *start, *end;
2182 start = (
const char *)ec->last_error.error_bytes_start;
2183 end = start + ec->last_error.error_bytes_len;
2184 n = rb_enc_precise_mbclen(start, end, utf8);
2187 unsigned int cc = rb_enc_mbc_to_codepoint(start, end, utf8);
2188 dumped = rb_sprintf(
"U+%04X", cc);
2193 if (strcmp(ec->last_error.source_encoding,
2194 ec->source_encoding_name) == 0 &&
2195 strcmp(ec->last_error.destination_encoding,
2196 ec->destination_encoding_name) == 0) {
2197 mesg = rb_sprintf(
"%s from %s to %s",
2199 ec->last_error.source_encoding,
2200 ec->last_error.destination_encoding);
2204 mesg = rb_sprintf(
"%s to %s in conversion from %s",
2206 ec->last_error.destination_encoding,
2207 ec->source_encoding_name);
2208 for (i = 0; i < ec->num_trans; i++) {
2210 if (!DECORATOR_P(
tr->src_encoding,
tr->dst_encoding))
2211 rb_str_catf(mesg,
" to %s",
2212 ec->elems[i].tc->transcoder->dst_encoding);
2215 exc =
rb_exc_new3(rb_eUndefinedConversionError, mesg);
2216 idx = rb_enc_find_index(ec->last_error.source_encoding);
2218 rb_enc_associate_index(bytes, idx);
2227 int idx = rb_enc_find_index(ec->last_error.source_encoding);
2229 rb_ivar_set(exc, id_source_encoding, rb_enc_from_encoding(rb_enc_from_index(idx)));
2230 idx = rb_enc_find_index(ec->last_error.destination_encoding);
2232 rb_ivar_set(exc, id_destination_encoding, rb_enc_from_encoding(rb_enc_from_index(idx)));
2239 unsigned char *(*resize_destination)(
VALUE,
size_t,
size_t),
2241 unsigned char **out_start_ptr,
2242 unsigned char **out_pos,
2243 unsigned char **out_stop_ptr)
2245 size_t len = (*out_pos - *out_start_ptr);
2246 size_t new_len = (
len + max_output) * 2;
2247 *out_start_ptr = resize_destination(destination,
len, new_len);
2248 *out_pos = *out_start_ptr +
len;
2249 *out_stop_ptr = *out_start_ptr + new_len;
2257 const unsigned char *replacement;
2258 const char *repl_enc;
2259 const char *ins_enc;
2262 if (ec->replacement_str)
2269 tr = tc->transcoder;
2270 rb_enc_find(
tr->dst_encoding);
2271 replacement = (
const unsigned char *)get_replacement_character(ins_enc, &
len, &repl_enc);
2274 replacement = (
unsigned char *)
"?";
2279 ec->replacement_str = replacement;
2280 ec->replacement_len =
len;
2281 ec->replacement_enc = repl_enc;
2282 ec->replacement_allocated = 0;
2288 const unsigned char *str,
size_t len,
const char *encname)
2290 unsigned char *str2;
2292 const char *encname2;
2296 if (!*encname2 || encoding_equal(encname, encname2)) {
2303 str2 = allocate_converted_string(encname, encname2, str,
len, NULL, 0, &len2);
2308 if (ec->replacement_allocated) {
2309 xfree((
void *)ec->replacement_str);
2311 ec->replacement_allocated = 1;
2312 ec->replacement_str = str2;
2313 ec->replacement_len = len2;
2314 ec->replacement_enc = encname2;
2323 if (make_replacement(ec) == -1)
2334#define hash_fallback rb_hash_aref
2361transcode_loop_fallback_try(
VALUE a)
2365 VALUE ret = args->fallback_func(args->fallback, args->rep);
2367 if (!UNDEF_P(ret) && !
NIL_P(ret)) {
2375transcode_loop(
const unsigned char **in_pos,
unsigned char **out_pos,
2376 const unsigned char *in_stop,
unsigned char *out_stop,
2378 unsigned char *(*resize_destination)(
VALUE,
size_t,
size_t),
2379 const char *src_encoding,
2380 const char *dst_encoding,
2388 unsigned char *out_start = *out_pos;
2393 const unsigned char *source_start = *in_pos;
2394 long source_len = in_stop - *in_pos;
2400 if (!
NIL_P(ecopts) && RB_TYPE_P(ecopts,
T_HASH)) {
2401 fallback = rb_hash_aref(ecopts, sym_fallback);
2402 if (RB_TYPE_P(fallback,
T_HASH)) {
2403 fallback_func = hash_fallback;
2406 fallback_func = proc_fallback;
2409 fallback_func = method_fallback;
2412 fallback_func = aref_fallback;
2415 last_tc = ec->last_tc;
2416 max_output = last_tc ? last_tc->transcoder->max_output : 1;
2422 VALUE rep = rb_enc_str_new(
2423 (
const char *)ec->last_error.error_bytes_start,
2424 ec->last_error.error_bytes_len,
2425 rb_enc_find(ec->last_error.source_encoding));
2429 .fallback_func = fallback_func,
2430 .fallback = fallback,
2435 rep = rb_protect(transcode_loop_fallback_try, (
VALUE)&args, &state);
2444 if ((
const unsigned char *)RSTRING_PTR(source) != source_start ||
2445 RSTRING_LEN(source) != source_len) {
2450 if (!UNDEF_P(rep) && !
NIL_P(rep)) {
2452 RSTRING_LEN(rep), rb_enc_name(rb_enc_get(rep)));
2453 if ((
int)ret == -1) {
2455 rb_raise(rb_eArgError,
"too big fallback string");
2464 exc = make_econv_exception(ec);
2470 more_output_buffer(destination, resize_destination, max_output, &out_start, out_pos, &out_stop);
2480transcode_loop(
const unsigned char **in_pos,
unsigned char **out_pos,
2481 const unsigned char *in_stop,
unsigned char *out_stop,
2483 unsigned char *(*resize_destination)(
VALUE,
size_t,
size_t),
2484 const char *src_encoding,
2485 const char *dst_encoding,
2493 unsigned char *out_start = *out_pos;
2494 const unsigned char *
ptr;
2502 last_tc = ec->last_tc;
2503 max_output = last_tc ? last_tc->transcoder->max_output : 1;
2508 unsigned char input_byte;
2509 const unsigned char *p = &input_byte;
2512 if (
ptr < in_stop) {
2523 if (&input_byte != p)
2524 ptr += p - &input_byte;
2529 exc = make_econv_exception(ec);
2535 more_output_buffer(destination, resize_destination, max_output, &out_start, out_pos, &out_stop);
2556static unsigned char *
2557str_transcoding_resize(
VALUE destination,
size_t len,
size_t new_len)
2559 rb_str_resize(destination, new_len);
2560 return (
unsigned char *)RSTRING_PTR(destination);
2564econv_opts(
VALUE opt,
int ecflags)
2567 int newlineflag = 0;
2569 v = rb_hash_aref(opt, sym_invalid);
2572 else if (v==sym_replace) {
2576 rb_raise(rb_eArgError,
"unknown value for invalid character option");
2579 v = rb_hash_aref(opt, sym_undef);
2582 else if (v==sym_replace) {
2586 rb_raise(rb_eArgError,
"unknown value for undefined character option");
2589 v = rb_hash_aref(opt, sym_replace);
2594 v = rb_hash_aref(opt, sym_xml);
2599 else if (v==sym_attr) {
2603 rb_raise(rb_eArgError,
"unexpected value for xml option: %"PRIsVALUE,
rb_sym2str(v));
2606 rb_raise(rb_eArgError,
"unexpected value for xml option");
2610#ifdef ENABLE_ECONV_NEWLINE_OPTION
2611 v = rb_hash_aref(opt, sym_newline);
2615 if (v == sym_universal) {
2618 else if (v == sym_crlf) {
2621 else if (v == sym_cr) {
2624 else if (v == sym_lf) {
2628 rb_raise(rb_eArgError,
"unexpected value for newline option: %"PRIsVALUE,
2632 rb_raise(rb_eArgError,
"unexpected value for newline option");
2639 v = rb_hash_aref(opt, sym_universal_newline);
2642 newlineflag |= !
NIL_P(v);
2644 v = rb_hash_aref(opt, sym_crlf_newline);
2647 newlineflag |= !
NIL_P(v);
2649 v = rb_hash_aref(opt, sym_cr_newline);
2652 newlineflag |= !
NIL_P(v);
2654 v = rb_hash_aref(opt, sym_lf_newline);
2657 newlineflag |= !
NIL_P(v);
2659 switch (newlineflag) {
2662 ecflags |= setflags;
2666 rb_warning(
":newline option precedes other newline options");
2680 if (
NIL_P(opthash)) {
2684 ecflags = econv_opts(opthash, ecflags);
2686 v = rb_hash_aref(opthash, sym_replace);
2689 if (is_broken_string(v)) {
2691 rb_raise(rb_eArgError,
"replacement string is broken: %s as %s",
2693 rb_enc_name(rb_enc_get(v)));
2696 newhash = rb_hash_new();
2697 rb_hash_aset(newhash, sym_replace, v);
2700 v = rb_hash_aref(opthash, sym_fallback);
2702 VALUE h = rb_check_hash_type(v);
2707 newhash = rb_hash_new();
2708 rb_hash_aset(newhash, sym_fallback, v);
2712 if (!
NIL_P(newhash))
2713 rb_hash_freeze(newhash);
2731 if (
NIL_P(opthash)) {
2736 rb_bug(
"rb_econv_open_opts called with invalid opthash");
2737 replacement = rb_hash_aref(opthash, sym_replace);
2740 ec =
rb_econv_open(source_encoding, destination_encoding, ecflags);
2742 if (!
NIL_P(replacement)) {
2744 rb_encoding *enc = rb_enc_get(replacement);
2747 (
const unsigned char *)RSTRING_PTR(replacement),
2748 RSTRING_LEN(replacement),
2760enc_arg(
VALUE *arg,
const char **name_p, rb_encoding **enc_p)
2767 if (((encidx = rb_to_encoding_index(encval = *arg)) < 0) ||
2768 !(enc = rb_enc_from_index(encidx))) {
2774 n = rb_enc_name(enc);
2785 const char **sname_p, rb_encoding **senc_p,
2786 const char **dname_p, rb_encoding **denc_p)
2788 rb_encoding *senc, *denc;
2789 const char *sname, *dname;
2790 int sencidx, dencidx;
2792 dencidx = enc_arg(arg1, &dname, &denc);
2795 sencidx = rb_enc_get_index(str);
2796 senc = rb_enc_from_index(sencidx);
2797 sname = rb_enc_name(senc);
2800 sencidx = enc_arg(arg2, &sname, &senc);
2811str_transcode0(
int argc,
VALUE *argv,
VALUE *self,
int ecflags,
VALUE ecopts)
2817 unsigned char *buf, *bp, *sp;
2818 const unsigned char *fromp;
2819 rb_encoding *senc, *denc;
2820 const char *sname, *dname;
2822 int explicitly_invalid_replace = TRUE;
2824 rb_check_arity(argc, 0, 2);
2827 arg1 = rb_enc_default_internal();
2829 if (!ecflags)
return -1;
2830 arg1 = rb_obj_encoding(str);
2833 explicitly_invalid_replace = FALSE;
2840 arg2 = argc<=1 ?
Qnil : argv[1];
2841 dencidx = str_transcode_enc_args(str, &arg1, &arg2, &sname, &senc, &dname, &denc);
2847 if (senc && senc == denc) {
2850 if (!
NIL_P(ecopts)) {
2851 rep = rb_hash_aref(ecopts, sym_replace);
2853 dest = rb_enc_str_scrub(senc, str, rep);
2854 if (
NIL_P(dest)) dest = str;
2858 return NIL_P(arg2) ? -1 : dencidx;
2860 if (senc && denc && rb_enc_asciicompat(senc) && rb_enc_asciicompat(denc)) {
2861 if (is_ascii_string(str)) {
2865 if (encoding_equal(sname, dname)) {
2866 return NIL_P(arg2) ? -1 : dencidx;
2870 if (senc && denc && !rb_enc_asciicompat(senc) && !rb_enc_asciicompat(denc)) {
2871 rb_encoding *utf8 = rb_utf8_encoding();
2876 if (encoding_equal(sname, dname)) {
2882 fromp = sp = (
unsigned char *)RSTRING_PTR(str);
2883 slen = RSTRING_LEN(str);
2886 bp = (
unsigned char *)RSTRING_PTR(dest);
2888 transcode_loop(&fromp, &bp, (sp+slen), (bp+blen), dest, str_transcoding_resize, sname, dname, ecflags, ecopts, str);
2889 if (fromp != sp+slen) {
2890 rb_raise(rb_eArgError,
"not fully converted, %"PRIdPTRDIFF
" bytes left", sp+slen-fromp);
2892 buf = (
unsigned char *)RSTRING_PTR(dest);
2898 dencidx = rb_define_dummy_encoding(dname);
2908str_transcode(
int argc,
VALUE *argv,
VALUE *self)
2914 argc =
rb_scan_args(argc, argv,
"02:", NULL, NULL, &opt);
2918 return str_transcode0(argc, argv, self, ecflags, ecopts);
2922str_encode_associate(
VALUE str,
int encidx)
2926 rb_enc_associate_index(str, encidx);
2929 if (rb_enc_asciicompat(rb_enc_from_index(encidx))) {
2950str_encode_bang(
int argc,
VALUE *argv,
VALUE str)
2955 rb_check_frozen(str);
2958 encidx = str_transcode(argc, argv, &newstr);
2960 if (encidx < 0)
return str;
2961 if (newstr == str) {
2962 rb_enc_associate_index(str, encidx);
2966 return str_encode_associate(str, encidx);
2984 int encidx = str_transcode(argc, argv, &newstr);
2985 return encoded_dup(newstr, str, encidx);
2994 int encidx = str_transcode0(argc, argv, &newstr, ecflags, ecopts);
2995 return encoded_dup(newstr, str, encidx);
2999encoded_dup(
VALUE newstr,
VALUE str,
int encidx)
3002 if (newstr == str) {
3004 rb_enc_associate_index(newstr, encidx);
3010 return str_encode_associate(newstr, encidx);
3019econv_free(
void *
ptr)
3026econv_memsize(
const void *
ptr)
3033 {0, econv_free, econv_memsize,},
3034 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
3038econv_s_allocate(
VALUE klass)
3044make_dummy_encoding(
const char *name)
3048 idx = rb_define_dummy_encoding(name);
3049 enc = rb_enc_from_index(idx);
3054make_encoding(
const char *name)
3057 enc = rb_enc_find(name);
3060 if (rb_enc_registered(name)) {
3064 enc = make_dummy_encoding(name);
3072make_encobj(
const char *name)
3074 return rb_enc_from_encoding(make_encoding(name));
3096econv_s_asciicompat_encoding(
VALUE klass,
VALUE arg)
3098 const char *arg_name, *result_name;
3099 rb_encoding *arg_enc, *result_enc;
3102 enc_arg(&arg, &arg_name, &arg_enc);
3105 result_enc = make_encoding(result_name);
3106 enc = rb_enc_from_encoding(result_enc);
3112econv_args(
int argc,
VALUE *argv,
3114 const char **sname_p,
const char **dname_p,
3115 rb_encoding **senc_p, rb_encoding **denc_p,
3119 VALUE opt, flags_v, ecopts;
3121 const char *sname, *dname;
3122 rb_encoding *senc, *denc;
3125 argc =
rb_scan_args(argc, argv,
"21:", snamev_p, dnamev_p, &flags_v, &opt);
3127 if (!
NIL_P(flags_v)) {
3129 rb_error_arity(argc + 1, 2, 3);
3134 else if (!
NIL_P(opt)) {
3143 sidx = rb_to_encoding_index(*snamev_p);
3145 senc = rb_enc_from_index(sidx);
3152 didx = rb_to_encoding_index(*dnamev_p);
3154 denc = rb_enc_from_index(didx);
3167 *ecflags_p = ecflags;
3172decorate_convpath(
VALUE convpath,
int ecflags)
3175 const char *decorators[MAX_ECFLAGS_DECORATORS];
3179 num_decorators = decorator_names(ecflags, decorators);
3180 if (num_decorators == -1)
3183 len = n = RARRAY_LENINT(convpath);
3186 if (RB_TYPE_P(pair,
T_ARRAY)) {
3187 const char *sname = rb_enc_name(rb_to_encoding(
RARRAY_AREF(pair, 0)));
3188 const char *dname = rb_enc_name(rb_to_encoding(
RARRAY_AREF(pair, 1)));
3191 entry = get_transcoder_entry(sname, dname);
3192 tr = load_transcoder_entry(entry);
3195 if (!DECORATOR_P(
tr->src_encoding,
tr->dst_encoding) &&
3196 tr->asciicompat_type == asciicompat_encoder) {
3206 for (i = 0; i < num_decorators; i++)
3213search_convpath_i(
const char *sname,
const char *dname,
int depth,
void *arg)
3218 if (
NIL_P(*ary_p)) {
3222 if (DECORATOR_P(sname, dname)) {
3226 v =
rb_assoc_new(make_encobj(sname), make_encobj(dname));
3257econv_s_search_convpath(
int argc,
VALUE *argv,
VALUE klass)
3259 VALUE snamev, dnamev;
3260 const char *sname, *dname;
3261 rb_encoding *senc, *denc;
3266 econv_args(argc, argv, &snamev, &dnamev, &sname, &dname, &senc, &denc, &ecflags, &ecopts);
3269 transcode_search_path(sname, dname, search_convpath_i, &convpath);
3271 if (
NIL_P(convpath)) {
3278 if (decorate_convpath(convpath, ecflags) == -1) {
3297 transcode_search_path(from_encoding, to_encoding, search_convpath_i,
3299 return RTEST(convpath);
3309rb_econv_init_by_convpath_i(
const char *sname,
const char *dname,
int depth,
void *arg)
3317 ret = rb_econv_add_converter(a->ec, sname, dname, a->index);
3324rb_econv_init_by_convpath(
VALUE self,
VALUE convpath,
3325 const char **sname_p,
const char **dname_p,
3326 rb_encoding **senc_p, rb_encoding**denc_p)
3332 rb_encoding *senc = 0, *denc = 0;
3333 const char *sname, *dname;
3335 ec = rb_econv_alloc(RARRAY_LENINT(convpath));
3339 VALUE snamev, dnamev;
3344 rb_raise(rb_eArgError,
"not a 2-element array in convpath");
3346 enc_arg(&snamev, &sname, &senc);
3348 enc_arg(&dnamev, &dname, &denc);
3354 if (DECORATOR_P(sname, dname)) {
3355 ret = rb_econv_add_converter(ec, sname, dname, ec->num_trans);
3357 VALUE msg = rb_sprintf(
"decoration failed: %s", dname);
3364 int j = ec->num_trans;
3367 arg.index = ec->num_trans;
3369 ret = transcode_search_path(sname, dname, rb_econv_init_by_convpath_i, &arg);
3370 if (ret == -1 || arg.ret == -1) {
3371 VALUE msg = rb_sprintf(
"adding conversion failed: %s to %s", sname, dname);
3379 *sname_p = ec->elems[j].tc->transcoder->src_encoding;
3382 *dname_p = ec->elems[ec->num_trans-1].tc->transcoder->dst_encoding;
3393 ec->source_encoding_name = *sname_p;
3394 ec->destination_encoding_name = *dname_p;
3514 VALUE snamev, dnamev;
3515 const char *sname, *dname;
3516 rb_encoding *senc, *denc;
3526 ec = rb_econv_init_by_convpath(self, convpath, &sname, &dname, &senc, &denc);
3531 econv_args(argc, argv, &snamev, &dnamev, &sname, &dname, &senc, &denc, &ecflags, &ecopts);
3542 if (!DECORATOR_P(sname, dname)) {
3544 senc = make_dummy_encoding(sname);
3546 denc = make_dummy_encoding(dname);
3551 ec->source_encoding = senc;
3552 ec->destination_encoding = denc;
3570econv_inspect(
VALUE self)
3577 return rb_sprintf(
"#<%s: uninitialized>", cname);
3579 const char *sname = ec->source_encoding_name;
3580 const char *dname = ec->destination_encoding_name;
3582 str = rb_sprintf(
"#<%s: ", cname);
3583 econv_description(sname, dname, ec->flags, str);
3590check_econv(
VALUE self)
3596 rb_raise(
rb_eTypeError,
"uninitialized encoding converter");
3602econv_get_encoding(rb_encoding *encoding)
3606 return rb_enc_from_encoding(encoding);
3616econv_source_encoding(
VALUE self)
3619 return econv_get_encoding(ec->source_encoding);
3629econv_destination_encoding(
VALUE self)
3632 return econv_get_encoding(ec->destination_encoding);
3658econv_convpath(
VALUE self)
3665 for (i = 0; i < ec->num_trans; i++) {
3668 if (DECORATOR_P(
tr->src_encoding,
tr->dst_encoding))
3671 v =
rb_assoc_new(make_encobj(
tr->src_encoding), make_encobj(
tr->dst_encoding));
3693 if (ec1->source_encoding_name != ec2->source_encoding_name &&
3694 strcmp(ec1->source_encoding_name, ec2->source_encoding_name))
3696 if (ec1->destination_encoding_name != ec2->destination_encoding_name &&
3697 strcmp(ec1->destination_encoding_name, ec2->destination_encoding_name))
3699 if (ec1->flags != ec2->flags)
return Qfalse;
3700 if (ec1->replacement_enc != ec2->replacement_enc &&
3701 strcmp(ec1->replacement_enc, ec2->replacement_enc))
3703 if (ec1->replacement_len != ec2->replacement_len)
return Qfalse;
3704 if (ec1->replacement_str != ec2->replacement_str &&
3705 memcmp(ec1->replacement_str, ec2->replacement_str, ec2->replacement_len))
3708 if (ec1->num_trans != ec2->num_trans)
return Qfalse;
3709 for (i = 0; i < ec1->num_trans; i++) {
3710 if (ec1->elems[i].tc->transcoder != ec2->elems[i].tc->transcoder)
3826econv_primitive_convert(
int argc,
VALUE *argv,
VALUE self)
3828 VALUE input, output, output_byteoffset_v, output_bytesize_v, opt, flags_v;
3831 const unsigned char *ip, *is;
3832 unsigned char *op, *os;
3833 long output_byteoffset, output_bytesize;
3834 unsigned long output_byteend;
3837 argc =
rb_scan_args(argc, argv,
"23:", &input, &output, &output_byteoffset_v, &output_bytesize_v, &flags_v, &opt);
3839 if (
NIL_P(output_byteoffset_v))
3840 output_byteoffset = 0;
3842 output_byteoffset =
NUM2LONG(output_byteoffset_v);
3844 if (
NIL_P(output_bytesize_v))
3845 output_bytesize = 0;
3847 output_bytesize =
NUM2LONG(output_bytesize_v);
3849 if (!
NIL_P(flags_v)) {
3851 rb_error_arity(argc + 1, 2, 5);
3855 else if (!
NIL_P(opt)) {
3858 v = rb_hash_aref(opt, sym_partial_input);
3861 v = rb_hash_aref(opt, sym_after_output);
3872 rb_str_modify(output);
3874 if (
NIL_P(output_bytesize_v)) {
3877 if (!
NIL_P(input) && output_bytesize < RSTRING_LEN(input))
3878 output_bytesize = RSTRING_LEN(input);
3883 if (
NIL_P(output_byteoffset_v))
3884 output_byteoffset = RSTRING_LEN(output);
3886 if (output_byteoffset < 0)
3887 rb_raise(rb_eArgError,
"negative output_byteoffset");
3889 if (RSTRING_LEN(output) < output_byteoffset)
3890 rb_raise(rb_eArgError,
"output_byteoffset too big");
3892 if (output_bytesize < 0)
3893 rb_raise(rb_eArgError,
"negative output_bytesize");
3895 output_byteend = (
unsigned long)output_byteoffset +
3896 (
unsigned long)output_bytesize;
3898 if (output_byteend < (
unsigned long)output_byteoffset ||
3899 LONG_MAX < output_byteend)
3900 rb_raise(rb_eArgError,
"output_byteoffset+output_bytesize too big");
3903 rb_str_resize(output, output_byteend);
3909 ip = (
const unsigned char *)RSTRING_PTR(input);
3910 is = ip + RSTRING_LEN(input);
3913 op = (
unsigned char *)RSTRING_PTR(output) + output_byteoffset;
3914 os = op + output_bytesize;
3918 if (!
NIL_P(input)) {
3923 if (LONG_MAX / 2 < output_bytesize)
3924 rb_raise(rb_eArgError,
"too long conversion result");
3925 output_bytesize *= 2;
3926 output_byteoffset_v =
Qnil;
3930 if (ec->destination_encoding) {
3931 rb_enc_associate(output, ec->destination_encoding);
3934 return econv_result_to_symbol(res);
3972econv_convert(
VALUE self,
VALUE source_string)
3990 ret = econv_primitive_convert(ac, av, self);
3992 if (ret == sym_invalid_byte_sequence ||
3993 ret == sym_undefined_conversion ||
3994 ret == sym_incomplete_input) {
3995 VALUE exc = make_econv_exception(ec);
3999 if (ret == sym_finished) {
4000 rb_raise(rb_eArgError,
"converter already finished");
4003 if (ret != sym_source_buffer_empty) {
4004 rb_bug(
"unexpected result of econv_primitive_convert");
4022econv_finish(
VALUE self)
4038 ret = econv_primitive_convert(ac, av, self);
4040 if (ret == sym_invalid_byte_sequence ||
4041 ret == sym_undefined_conversion ||
4042 ret == sym_incomplete_input) {
4043 VALUE exc = make_econv_exception(ec);
4047 if (ret != sym_finished) {
4048 rb_bug(
"unexpected result of econv_primitive_convert");
4130econv_primitive_errinfo(
VALUE self)
4138 rb_ary_store(ary, 0, econv_result_to_symbol(ec->last_error.result));
4141 if (ec->last_error.source_encoding)
4144 if (ec->last_error.destination_encoding)
4147 if (ec->last_error.error_bytes_start) {
4148 rb_ary_store(ary, 3,
rb_str_new((
const char *)ec->last_error.error_bytes_start, ec->last_error.error_bytes_len));
4149 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));
4190 const char *insert_enc;
4198 string =
rb_str_encode(
string, rb_enc_from_encoding(rb_enc_find(insert_enc)), 0,
Qnil);
4200 ret =
rb_econv_insert_output(ec, (
const unsigned char *)RSTRING_PTR(
string), RSTRING_LEN(
string), insert_enc);
4202 rb_raise(rb_eArgError,
"too big string");
4233econv_putback(
int argc,
VALUE *argv,
VALUE self)
4240 if (!rb_check_arity(argc, 0, 1) ||
NIL_P(max = argv[0])) {
4246 if (putbackable < n)
4253 if (ec->source_encoding) {
4254 rb_enc_associate(str, ec->source_encoding);
4281econv_last_error(
VALUE self)
4286 exc = make_econv_exception(ec);
4305econv_get_replacement(
VALUE self)
4311 ret = make_replacement(ec);
4313 rb_raise(rb_eUndefinedConversionError,
"replacement character setup failed");
4316 enc = rb_enc_find(ec->replacement_enc);
4317 return rb_enc_str_new((
const char *)ec->replacement_str, (
long)ec->replacement_len, enc);
4339 enc = rb_enc_get(
string);
4342 (
const unsigned char *)RSTRING_PTR(
string),
4343 RSTRING_LEN(
string),
4348 rb_raise(rb_eUndefinedConversionError,
"replacement character setup failed");
4357 return make_econv_exception(ec);
4365 exc = make_econv_exception(ec);
4378ecerr_source_encoding_name(
VALUE self)
4380 return rb_attr_get(self, id_source_encoding_name);
4404ecerr_source_encoding(
VALUE self)
4406 return rb_attr_get(self, id_source_encoding);
4416ecerr_destination_encoding_name(
VALUE self)
4418 return rb_attr_get(self, id_destination_encoding_name);
4428ecerr_destination_encoding(
VALUE self)
4430 return rb_attr_get(self, id_destination_encoding);
4449ecerr_error_char(
VALUE self)
4451 return rb_attr_get(self, id_error_char);
4470ecerr_error_bytes(
VALUE self)
4472 return rb_attr_get(self, id_error_bytes);
4482ecerr_readagain_bytes(
VALUE self)
4484 return rb_attr_get(self, id_readagain_bytes);
4512ecerr_incomplete_input(
VALUE self)
4514 return rb_attr_get(self, id_incomplete_input);
4542 transcoder_table = st_init_strcasetable();
4544 id_destination_encoding = rb_intern_const(
"destination_encoding");
4545 id_destination_encoding_name = rb_intern_const(
"destination_encoding_name");
4546 id_error_bytes = rb_intern_const(
"error_bytes");
4547 id_error_char = rb_intern_const(
"error_char");
4548 id_incomplete_input = rb_intern_const(
"incomplete_input");
4549 id_readagain_bytes = rb_intern_const(
"readagain_bytes");
4550 id_source_encoding = rb_intern_const(
"source_encoding");
4551 id_source_encoding_name = rb_intern_const(
"source_encoding_name");
4553 sym_invalid =
ID2SYM(rb_intern_const(
"invalid"));
4554 sym_undef =
ID2SYM(rb_intern_const(
"undef"));
4555 sym_replace =
ID2SYM(rb_intern_const(
"replace"));
4556 sym_fallback =
ID2SYM(rb_intern_const(
"fallback"));
4557 sym_xml =
ID2SYM(rb_intern_const(
"xml"));
4558 sym_text =
ID2SYM(rb_intern_const(
"text"));
4559 sym_attr =
ID2SYM(rb_intern_const(
"attr"));
4561 sym_invalid_byte_sequence =
ID2SYM(rb_intern_const(
"invalid_byte_sequence"));
4562 sym_undefined_conversion =
ID2SYM(rb_intern_const(
"undefined_conversion"));
4563 sym_destination_buffer_full =
ID2SYM(rb_intern_const(
"destination_buffer_full"));
4564 sym_source_buffer_empty =
ID2SYM(rb_intern_const(
"source_buffer_empty"));
4565 sym_finished =
ID2SYM(rb_intern_const(
"finished"));
4566 sym_after_output =
ID2SYM(rb_intern_const(
"after_output"));
4567 sym_incomplete_input =
ID2SYM(rb_intern_const(
"incomplete_input"));
4568 sym_universal_newline =
ID2SYM(rb_intern_const(
"universal_newline"));
4569 sym_crlf_newline =
ID2SYM(rb_intern_const(
"crlf_newline"));
4570 sym_cr_newline =
ID2SYM(rb_intern_const(
"cr_newline"));
4571 sym_lf_newline =
ID2SYM(rb_intern(
"lf_newline"));
4572 sym_partial_input =
ID2SYM(rb_intern_const(
"partial_input"));
4574#ifdef ENABLE_ECONV_NEWLINE_OPTION
4575 sym_newline =
ID2SYM(rb_intern_const(
"newline"));
4576 sym_universal =
ID2SYM(rb_intern_const(
"universal"));
4577 sym_crlf =
ID2SYM(rb_intern_const(
"crlf"));
4578 sym_cr =
ID2SYM(rb_intern_const(
"cr"));
4579 sym_lf =
ID2SYM(rb_intern_const(
"lf"));
4586InitVM_transcode(
void)
4602 rb_define_method(rb_cEncodingConverter,
"source_encoding", econv_source_encoding, 0);
4603 rb_define_method(rb_cEncodingConverter,
"destination_encoding", econv_destination_encoding, 0);
4604 rb_define_method(rb_cEncodingConverter,
"primitive_convert", econv_primitive_convert, -1);
4607 rb_define_method(rb_cEncodingConverter,
"primitive_errinfo", econv_primitive_errinfo, 0);
4608 rb_define_method(rb_cEncodingConverter,
"insert_output", econv_insert_output, 1);
4610 rb_define_method(rb_cEncodingConverter,
"last_error", econv_last_error, 0);
4611 rb_define_method(rb_cEncodingConverter,
"replacement", econv_get_replacement, 0);
4612 rb_define_method(rb_cEncodingConverter,
"replacement=", econv_set_replacement, 1);
4690 rb_define_method(rb_eUndefinedConversionError,
"source_encoding_name", ecerr_source_encoding_name, 0);
4691 rb_define_method(rb_eUndefinedConversionError,
"destination_encoding_name", ecerr_destination_encoding_name, 0);
4692 rb_define_method(rb_eUndefinedConversionError,
"source_encoding", ecerr_source_encoding, 0);
4693 rb_define_method(rb_eUndefinedConversionError,
"destination_encoding", ecerr_destination_encoding, 0);
4694 rb_define_method(rb_eUndefinedConversionError,
"error_char", ecerr_error_char, 0);
4696 rb_define_method(rb_eInvalidByteSequenceError,
"source_encoding_name", ecerr_source_encoding_name, 0);
4697 rb_define_method(rb_eInvalidByteSequenceError,
"destination_encoding_name", ecerr_destination_encoding_name, 0);
4698 rb_define_method(rb_eInvalidByteSequenceError,
"source_encoding", ecerr_source_encoding, 0);
4699 rb_define_method(rb_eInvalidByteSequenceError,
"destination_encoding", ecerr_destination_encoding, 0);
4700 rb_define_method(rb_eInvalidByteSequenceError,
"error_bytes", ecerr_error_bytes, 0);
4701 rb_define_method(rb_eInvalidByteSequenceError,
"readagain_bytes", ecerr_readagain_bytes, 0);
4702 rb_define_method(rb_eInvalidByteSequenceError,
"incomplete_input?", ecerr_incomplete_input, 0);
ruby_coderange_type
What rb_enc_str_coderange() returns.
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Retrieves argument from argc and argv to given VALUE references according to the format string.
#define ECONV_XML_ATTR_QUOTE_DECORATOR
Old name of RUBY_ECONV_XML_ATTR_QUOTE_DECORATOR.
#define ECONV_AFTER_OUTPUT
Old name of RUBY_ECONV_AFTER_OUTPUT.
#define rb_str_new2
Old name of rb_str_new_cstr.
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
#define ENC_CODERANGE_VALID
Old name of RUBY_ENC_CODERANGE_VALID.
#define ECONV_UNIVERSAL_NEWLINE_DECORATOR
Old name of RUBY_ECONV_UNIVERSAL_NEWLINE_DECORATOR.
#define REALLOC_N
Old name of RB_REALLOC_N.
#define ALLOC
Old name of RB_ALLOC.
#define xfree
Old name of ruby_xfree.
#define INT2FIX
Old name of RB_INT2FIX.
#define OBJ_FROZEN
Old name of RB_OBJ_FROZEN.
#define ECONV_XML_ATTR_CONTENT_DECORATOR
Old name of RUBY_ECONV_XML_ATTR_CONTENT_DECORATOR.
#define rb_str_cat2
Old name of rb_str_cat_cstr.
#define ECONV_INVALID_MASK
Old name of RUBY_ECONV_INVALID_MASK.
#define ECONV_CRLF_NEWLINE_DECORATOR
Old name of RUBY_ECONV_CRLF_NEWLINE_DECORATOR.
#define xrealloc
Old name of ruby_xrealloc.
#define ID2SYM
Old name of RB_ID2SYM.
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
#define ECONV_UNDEF_REPLACE
Old name of RUBY_ECONV_UNDEF_REPLACE.
#define ECONV_XML_TEXT_DECORATOR
Old name of RUBY_ECONV_XML_TEXT_DECORATOR.
#define rb_ary_new4
Old name of rb_ary_new_from_values.
#define ENC_CODERANGE_UNKNOWN
Old name of RUBY_ENC_CODERANGE_UNKNOWN.
#define ECONV_CR_NEWLINE_DECORATOR
Old name of RUBY_ECONV_CR_NEWLINE_DECORATOR.
#define xmalloc
Old name of ruby_xmalloc.
#define ECONV_INVALID_REPLACE
Old name of RUBY_ECONV_INVALID_REPLACE.
#define T_HASH
Old name of RUBY_T_HASH.
#define ALLOC_N
Old name of RB_ALLOC_N.
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
#define rb_exc_new3
Old name of rb_exc_new_str.
#define ECONV_UNDEF_MASK
Old name of RUBY_ECONV_UNDEF_MASK.
#define Qtrue
Old name of RUBY_Qtrue.
#define ECONV_PARTIAL_INPUT
Old name of RUBY_ECONV_PARTIAL_INPUT.
#define NUM2INT
Old name of RB_NUM2INT.
#define ECONV_ERROR_HANDLER_MASK
Old name of RUBY_ECONV_ERROR_HANDLER_MASK.
#define INT2NUM
Old name of RB_INT2NUM.
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
#define ECONV_LF_NEWLINE_DECORATOR
Old name of RUBY_ECONV_LF_NEWLINE_DECORATOR.
#define T_ARRAY
Old name of RUBY_T_ARRAY.
#define NIL_P
Old name of RB_NIL_P.
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
#define ECONV_UNDEF_HEX_CHARREF
Old name of RUBY_ECONV_UNDEF_HEX_CHARREF.
#define NUM2LONG
Old name of RB_NUM2LONG.
#define ECONV_NEWLINE_DECORATOR_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_MASK.
#define rb_ary_new2
Old name of rb_ary_new_capa.
#define ENC_CODERANGE_SET(obj, cr)
Old name of RB_ENC_CODERANGE_SET.
#define SYMBOL_P
Old name of RB_SYMBOL_P.
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
int rb_typeddata_is_kind_of(VALUE obj, const rb_data_type_t *data_type)
Checks if the given object is of given kind.
VALUE rb_eTypeError
TypeError exception.
VALUE rb_eRuntimeError
RuntimeError exception.
void * rb_check_typeddata(VALUE obj, const rb_data_type_t *data_type)
Identical to rb_typeddata_is_kind_of(), except it raises exceptions instead of returning false.
VALUE rb_exc_new_str(VALUE etype, VALUE str)
Identical to rb_exc_new_cstr(), except it takes a Ruby's string instead of C's.
VALUE rb_eEncodingError
EncodingError exception.
void rb_warning(const char *fmt,...)
Issues a warning.
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
VALUE rb_cEncoding
Encoding class.
VALUE rb_cString
String class.
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
Encoding conversion main routine.
int rb_enc_str_coderange(VALUE str)
Scans the passed string to collect its code range.
long rb_str_coderange_scan_restartable(const char *str, const char *end, rb_encoding *enc, int *cr)
Scans the passed string until it finds something odd.
int rb_econv_prepare_options(VALUE opthash, VALUE *ecopts, int ecflags)
Identical to rb_econv_prepare_opts(), except it additionally takes the initial value of flags.
VALUE rb_econv_open_exc(const char *senc, const char *denc, int ecflags)
Creates a rb_eConverterNotFoundError exception object (but does not raise).
const char * rb_econv_encoding_to_insert_output(rb_econv_t *ec)
Queries an encoding name which best suits for rb_econv_insert_output()'s last parameter.
int rb_econv_prepare_opts(VALUE opthash, VALUE *ecopts)
Splits a keyword arguments hash (that for instance String#encode took) into a set of enum ruby_econv_...
rb_econv_result_t rb_econv_convert(rb_econv_t *ec, const unsigned char **source_buffer_ptr, const unsigned char *source_buffer_end, unsigned char **destination_buffer_ptr, unsigned char *destination_buffer_end, int flags)
Converts a string from an encoding to another.
rb_econv_result_t
return value of rb_econv_convert()
@ econv_incomplete_input
The conversion stopped in middle of reading a character, possibly due to a partial read of a socket e...
@ econv_finished
The conversion stopped after converting everything.
@ econv_undefined_conversion
The conversion stopped when it found a character in the input which cannot be representable in the ou...
@ econv_after_output
The conversion stopped after writing something to somewhere, before reading everything.
@ econv_source_buffer_empty
The conversion stopped because there is no input.
@ econv_destination_buffer_full
The conversion stopped because there is no destination.
@ econv_invalid_byte_sequence
The conversion stopped when it found an invalid sequence.
int rb_econv_putbackable(rb_econv_t *ec)
Queries if rb_econv_putback() makes sense, i.e.
int rb_econv_has_convpath_p(const char *from_encoding, const char *to_encoding)
Queries if there is more than one way to convert between the passed two encodings.
rb_econv_t * rb_econv_open(const char *source_encoding, const char *destination_encoding, int ecflags)
Creates a new instance of struct rb_econv_t.
VALUE rb_econv_str_append(rb_econv_t *ec, VALUE src, VALUE dst, int flags)
Identical to rb_econv_str_convert(), except it appends the conversion result to the additionally pass...
VALUE rb_econv_substr_append(rb_econv_t *ec, VALUE src, long byteoff, long bytesize, VALUE dst, int flags)
Identical to rb_econv_str_append(), except it appends only a part of the passed string with conversio...
const char * rb_econv_asciicompat_encoding(const char *encname)
Queries the passed encoding's corresponding ASCII compatible encoding.
int rb_econv_insert_output(rb_econv_t *ec, const unsigned char *str, size_t len, const char *str_encoding)
Appends the passed string to the passed converter's output buffer.
VALUE rb_econv_str_convert(rb_econv_t *ec, VALUE src, int flags)
Identical to rb_econv_convert(), except it takes Ruby's string instead of C's pointer.
rb_econv_t * rb_econv_open_opts(const char *source_encoding, const char *destination_encoding, int ecflags, VALUE ecopts)
Identical to rb_econv_open(), except it additionally takes a hash of optional strings.
int rb_econv_decorate_at_last(rb_econv_t *ec, const char *decorator_name)
Identical to rb_econv_decorate_at_first(), except it adds to the opposite direction.
void rb_econv_binmode(rb_econv_t *ec)
This badly named function does not set the destination encoding to binary, but instead just nullifies...
int rb_econv_decorate_at_first(rb_econv_t *ec, const char *decorator_name)
"Decorate"s a converter.
VALUE rb_str_encode(VALUE str, VALUE to, int ecflags, VALUE ecopts)
Converts the contents of the passed string from its encoding to the passed one.
VALUE rb_econv_make_exception(rb_econv_t *ec)
This function makes sense right after rb_econv_convert() returns.
void rb_econv_check_error(rb_econv_t *ec)
This is a rb_econv_make_exception() + rb_exc_raise() combo.
VALUE rb_econv_substr_convert(rb_econv_t *ec, VALUE src, long byteoff, long bytesize, int flags)
Identical to rb_econv_str_convert(), except it converts only a part of the passed string.
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
VALUE rb_econv_append(rb_econv_t *ec, const char *bytesrc, long bytesize, VALUE dst, int flags)
Converts the passed C's pointer according to the passed converter, then append the conversion result ...
void rb_econv_putback(rb_econv_t *ec, unsigned char *p, int n)
Puts back the bytes.
int rb_econv_set_replacement(rb_econv_t *ec, const unsigned char *str, size_t len, const char *encname)
Assigns the replacement string.
VALUE rb_funcallv_public(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcallv(), except it only takes public methods into account.
VALUE rb_check_array_type(VALUE obj)
Try converting an object to its array representation using its to_ary method, if any.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Identical to rb_ary_new_from_values(), except it expects exactly two parameters.
void rb_ary_store(VALUE ary, long key, VALUE val)
Destructively stores the passed value to the passed array's passed index.
VALUE rb_proc_call(VALUE recv, VALUE args)
Evaluates the passed proc with the passed arguments.
VALUE rb_obj_is_method(VALUE recv)
Queries if the given object is a method.
VALUE rb_method_call(int argc, const VALUE *argv, VALUE recv)
Evaluates the passed method with the passed arguments.
VALUE rb_obj_is_proc(VALUE recv)
Queries if the given object is a proc.
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
void rb_str_shared_replace(VALUE dst, VALUE src)
Replaces the contents of the former with the latter.
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
VALUE rb_str_dup(VALUE str)
Duplicates a string.
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
void rb_str_modify_expand(VALUE str, long capa)
Identical to rb_str_modify(), except it additionally expands the capacity of the receiver.
VALUE rb_str_dump(VALUE str)
"Inverse" of rb_eval_string().
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
VALUE rb_str_drop_bytes(VALUE str, long len)
Shrinks the given string for the given number of bytes.
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
VALUE rb_sym2str(VALUE symbol)
Obtain a frozen string representation of a symbol (not including the leading colon).
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
int off
Offset inside of ptr.
int len
Length of the buffer.
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
#define ALLOCA_N(type, n)
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
#define RARRAY_LEN
Just another name of rb_array_len.
#define RARRAY_AREF(a, i)
#define DATA_PTR(obj)
Convenient getter macro.
#define StringValue(v)
Ensures that the parameter object is a String.
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
#define TypedData_Get_Struct(obj, type, data_type, sval)
Obtains a C struct from inside of a wrapper Ruby object.
#define TypedData_Wrap_Struct(klass, data_type, sval)
Converts sval, a pointer to your struct, into a Ruby object.
struct rb_data_type_struct rb_data_type_t
This is the struct that holds necessary info for a struct.
const char * rb_obj_classname(VALUE obj)
Queries the name of the class of the passed object.
#define InitVM(ext)
This macro is for internal use.
#define RTEST
This is an old name of RB_TEST.
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
uintptr_t VALUE
Type that represents a Ruby object.