Ruby 4.1.0dev (2026-09-07 revision 11ce3778c6eacc10897729314e5ab3bed7830971)
transcode.c (11ce3778c6eacc10897729314e5ab3bed7830971)
1/**********************************************************************
2
3 transcode.c -
4
5 $Author$
6 created at: Tue Oct 30 16:10:22 JST 2007
7
8 Copyright (C) 2007 Martin Duerst
9
10**********************************************************************/
11
12#include "ruby/internal/config.h"
13
14#include <ctype.h>
15
16#include "internal.h"
17#include "internal/array.h"
18#include "internal/inits.h"
19#include "internal/gc.h"
20#include "internal/object.h"
21#include "internal/string.h"
22#include "internal/transcode.h"
23#include "internal/encoding.h"
24#include "ruby/encoding.h"
25#include "vm_sync.h"
26
27#include "transcode_data.h"
28#include "id.h"
29
30#define ENABLE_ECONV_NEWLINE_OPTION 1
31
32/* VALUE rb_cEncoding = rb_define_class("Encoding", rb_cObject); */
33static VALUE rb_eUndefinedConversionError;
34static VALUE rb_eInvalidByteSequenceError;
35static VALUE rb_eConverterNotFoundError;
36
37VALUE rb_cEncodingConverter;
38
39static ID id_destination_encoding;
40static ID id_destination_encoding_name;
41static ID id_error_bytes;
42static ID id_error_char;
43static ID id_incomplete_input;
44static ID id_readagain_bytes;
45static ID id_source_encoding;
46static ID id_source_encoding_name;
47
48static VALUE sym_invalid, sym_undef, sym_replace, sym_fallback;
49static VALUE sym_xml, sym_text, sym_attr;
50static VALUE sym_universal_newline;
51static VALUE sym_crlf_newline;
52static VALUE sym_cr_newline;
53static VALUE sym_lf_newline;
54#ifdef ENABLE_ECONV_NEWLINE_OPTION
55static VALUE sym_newline, sym_universal, sym_crlf, sym_cr, sym_lf;
56#endif
57static VALUE sym_partial_input;
58
59static VALUE sym_invalid_byte_sequence;
60static VALUE sym_undefined_conversion;
61static VALUE sym_destination_buffer_full;
62static VALUE sym_source_buffer_empty;
63static VALUE sym_finished;
64static VALUE sym_after_output;
65static VALUE sym_incomplete_input;
66
67static unsigned char *
68allocate_converted_string(const char *sname, const char *dname,
69 const unsigned char *str, size_t len,
70 unsigned char *caller_dst_buf, size_t caller_dst_bufsize,
71 size_t *dst_len_ptr, size_t *dst_bufsize_ptr);
72
73/* dynamic structure, one per conversion (similar to iconv_t) */
74/* may carry conversion state (e.g. for iso-2022-jp) */
75typedef struct rb_transcoding {
76 const rb_transcoder *transcoder;
77
78 int flags;
79
80 int resume_position;
81 unsigned int next_table;
82 VALUE next_info;
83 unsigned char next_byte;
84 unsigned int output_index;
85
86 ssize_t recognized_len; /* already interpreted */
87 ssize_t readagain_len; /* not yet interpreted */
88 union {
89 unsigned char ary[8]; /* max_input <= sizeof(ary) */
90 unsigned char *ptr; /* length: max_input */
91 } readbuf; /* recognized_len + readagain_len used */
92
93 ssize_t writebuf_off;
94 ssize_t writebuf_len;
95 union {
96 unsigned char ary[8]; /* max_output <= sizeof(ary) */
97 unsigned char *ptr; /* length: max_output */
98 } writebuf;
99
100 union rb_transcoding_state_t { /* opaque data for stateful encoding */
101 void *ptr;
102 char ary[sizeof(double) > sizeof(void*) ? sizeof(double) : sizeof(void*)];
103 double dummy_for_alignment;
104 } state;
106#define TRANSCODING_READBUF(tc) \
107 ((tc)->transcoder->max_input <= (int)sizeof((tc)->readbuf.ary) ? \
108 (tc)->readbuf.ary : \
109 (tc)->readbuf.ptr)
110#define TRANSCODING_WRITEBUF(tc) \
111 ((tc)->transcoder->max_output <= (int)sizeof((tc)->writebuf.ary) ? \
112 (tc)->writebuf.ary : \
113 (tc)->writebuf.ptr)
114#define TRANSCODING_WRITEBUF_SIZE(tc) \
115 ((tc)->transcoder->max_output <= (int)sizeof((tc)->writebuf.ary) ? \
116 sizeof((tc)->writebuf.ary) : \
117 (size_t)(tc)->transcoder->max_output)
118#define TRANSCODING_STATE_EMBED_MAX ((int)sizeof(union rb_transcoding_state_t))
119#define TRANSCODING_STATE(tc) \
120 ((tc)->transcoder->state_size <= (int)sizeof((tc)->state) ? \
121 (tc)->state.ary : \
122 (tc)->state.ptr)
123
124typedef struct {
125 struct rb_transcoding *tc;
126 unsigned char *out_buf_start;
127 unsigned char *out_data_start;
128 unsigned char *out_data_end;
129 unsigned char *out_buf_end;
130 rb_econv_result_t last_result;
132
134 int flags;
135 int started; /* bool */
136
137 const char *source_encoding_name;
138 const char *destination_encoding_name;
139
140 const unsigned char *replacement_str;
141 size_t replacement_len;
142 size_t replacement_bufsize;
143 const char *replacement_enc;
144
145 unsigned char *in_buf_start;
146 unsigned char *in_data_start;
147 unsigned char *in_data_end;
148 unsigned char *in_buf_end;
149 rb_econv_elem_t *elems;
150 int replacement_allocated; /* bool */
151 int num_allocated;
152 int num_trans;
153 int num_finished;
154 struct rb_transcoding *last_tc;
155
156 /* last error */
157 struct {
158 rb_econv_result_t result;
159 struct rb_transcoding *error_tc;
160 const char *source_encoding;
161 const char *destination_encoding;
162 const unsigned char *error_bytes_start;
163 size_t error_bytes_len;
164 size_t readagain_len;
165 } last_error;
166
167 /* The following fields are only for Encoding::Converter.
168 * rb_econv_open set them NULL. */
169 rb_encoding *source_encoding;
170 rb_encoding *destination_encoding;
171};
172
173/*
174 * Dispatch data and logic
175 */
176
177#define DECORATOR_P(sname, dname) (*(sname) == '\0')
178
179typedef struct {
180 const char *sname;
181 const char *dname;
182 const char *lib; /* null means no need to load a library */
183 const rb_transcoder *transcoder;
185
186static st_table *transcoder_table;
187
188static int
189free_inner_transcode_i(st_data_t key, st_data_t val, st_data_t arg)
190{
191 SIZED_FREE((transcoder_entry_t *)val);
192 return ST_DELETE;
193}
194
195static int
196free_transcode_i(st_data_t key, st_data_t val, st_data_t arg)
197{
198 st_foreach((void *)val, free_inner_transcode_i, 0);
199 st_free_table((void *)val);
200 return ST_DELETE;
201}
202
203void
204rb_free_transcoder_table(void)
205{
206 st_foreach(transcoder_table, free_transcode_i, 0);
207 st_free_table(transcoder_table);
208}
209
210static transcoder_entry_t *
211make_transcoder_entry(const char *sname, const char *dname)
212{
213 st_data_t val;
214 st_table *table2;
215
216 RB_VM_LOCKING() {
217 if (!st_lookup(transcoder_table, (st_data_t)sname, &val)) {
218 val = (st_data_t)st_init_strcasetable();
219 st_add_direct(transcoder_table, (st_data_t)sname, val);
220 }
221 table2 = (st_table *)val;
222 if (!st_lookup(table2, (st_data_t)dname, &val)) {
224 entry->sname = sname;
225 entry->dname = dname;
226 entry->lib = NULL;
227 entry->transcoder = NULL;
228 val = (st_data_t)entry;
229 st_add_direct(table2, (st_data_t)dname, val);
230 }
231 }
232 return (transcoder_entry_t *)val;
233}
234
235static transcoder_entry_t *
236get_transcoder_entry(const char *sname, const char *dname)
237{
238 st_data_t val = 0;
239 st_table *table2;
240 RB_VM_LOCKING() {
241 if (st_lookup(transcoder_table, (st_data_t)sname, &val)) {
242 table2 = (st_table *)val;
243 if (!st_lookup(table2, (st_data_t)dname, &val)) {
244 val = 0;
245 }
246 }
247 }
248 return (transcoder_entry_t *)val;
249}
250
251void
252rb_register_transcoder(const rb_transcoder *tr)
253{
254 const char *const sname = tr->src_encoding;
255 const char *const dname = tr->dst_encoding;
256
257 transcoder_entry_t *entry;
258
259 RB_VM_LOCKING() {
260 entry = make_transcoder_entry(sname, dname);
261 if (entry->transcoder) {
262 rb_raise(rb_eArgError, "transcoder from %s to %s has been already registered",
263 sname, dname);
264 }
265 entry->transcoder = tr;
266 }
267}
268
269static void
270declare_transcoder(const char *sname, const char *dname, const char *lib)
271{
272 transcoder_entry_t *entry;
273
274 entry = make_transcoder_entry(sname, dname);
275 entry->lib = lib;
276}
277
278static const char transcoder_lib_prefix[] = "enc/trans/";
279
280void
281rb_declare_transcoder(const char *enc1, const char *enc2, const char *lib)
282{
283 if (!lib) {
284 rb_raise(rb_eArgError, "invalid library name - (null)");
285 }
286 declare_transcoder(enc1, enc2, lib);
287}
288
289#define encoding_equal(enc1, enc2) (STRCASECMP((enc1), (enc2)) == 0)
290
291typedef struct search_path_queue_tag {
292 struct search_path_queue_tag *next;
293 const char *enc;
295
296typedef struct {
297 st_table *visited;
298 search_path_queue_t *queue;
299 search_path_queue_t **queue_last_ptr;
300 const char *base_enc;
302
303static int
304transcode_search_path_i(st_data_t key, st_data_t val, st_data_t arg)
305{
306 const char *dname = (const char *)key;
309
310 if (st_lookup(bfs->visited, (st_data_t)dname, &val)) {
311 return ST_CONTINUE;
312 }
313
315 q->enc = dname;
316 q->next = NULL;
317 *bfs->queue_last_ptr = q;
318 bfs->queue_last_ptr = &q->next;
319
320 st_add_direct(bfs->visited, (st_data_t)dname, (st_data_t)bfs->base_enc);
321 return ST_CONTINUE;
322}
323
324static int
325transcode_search_path(const char *sname, const char *dname,
326 void (*callback)(const char *sname, const char *dname, int depth, void *arg),
327 void *arg)
328{
331 st_data_t val;
332 st_table *table2;
333 int pathlen = -1;
334 bool found = false;
335 bool lookup_res;
336
337 if (encoding_equal(sname, dname))
338 return -1;
339
341 q->enc = sname;
342 q->next = NULL;
343 bfs.queue_last_ptr = &q->next;
344 bfs.queue = q;
345
346 bfs.visited = st_init_strcasetable(); // due to base encodings, we need to do search in a loop
347 st_add_direct(bfs.visited, (st_data_t)sname, (st_data_t)NULL);
348
349 RB_VM_LOCKING() {
350 while (bfs.queue) {
351 q = bfs.queue;
352 bfs.queue = q->next;
353 if (!bfs.queue) {
354 bfs.queue_last_ptr = &bfs.queue;
355 }
356
357 lookup_res = st_lookup(transcoder_table, (st_data_t)q->enc, &val); // src => table2
358 if (!lookup_res) {
359 SIZED_FREE(q);
360 continue;
361 }
362 table2 = (st_table *)val;
363
364 if (st_lookup(table2, (st_data_t)dname, &val)) { // dest => econv
365 st_add_direct(bfs.visited, (st_data_t)dname, (st_data_t)q->enc);
366 SIZED_FREE(q);
367 found = true;
368 break;
369 }
370
371 bfs.base_enc = q->enc;
372 st_foreach(table2, transcode_search_path_i, (st_data_t)&bfs);
373
374 bfs.base_enc = NULL;
375 SIZED_FREE(q);
376 }
377 }
378
379 while (bfs.queue) {
380 q = bfs.queue;
381 bfs.queue = q->next;
382 SIZED_FREE(q);
383 }
384
385 if (found) {
386 const char *enc = dname;
387 int depth;
388 pathlen = 0;
389 while (1) {
390 st_lookup(bfs.visited, (st_data_t)enc, &val);
391 if (!val)
392 break;
393 pathlen++;
394 enc = (const char *)val;
395 }
396 depth = pathlen;
397 enc = dname;
398 while (1) {
399 st_lookup(bfs.visited, (st_data_t)enc, &val);
400 if (!val)
401 break;
402 callback((const char *)val, enc, --depth, arg);
403 enc = (const char *)val;
404 }
405 }
406
407 st_free_table(bfs.visited);
408
409 return pathlen; /* is -1 if not found */
410}
411
412int rb_require_internal_silent(VALUE fname);
413
414static const rb_transcoder *
415load_transcoder_entry(transcoder_entry_t *entry)
416{
417 ASSERT_vm_unlocking();
418 if (entry->transcoder)
419 return entry->transcoder;
420
421 if (entry->lib) {
422 const char *const lib = entry->lib;
423 const size_t len = strlen(lib);
424 const size_t total_len = sizeof(transcoder_lib_prefix) - 1 + len;
425 const VALUE fn = rb_str_new(0, total_len);
426 char *const path = RSTRING_PTR(fn);
427
428 memcpy(path, transcoder_lib_prefix, sizeof(transcoder_lib_prefix) - 1);
429 memcpy(path + sizeof(transcoder_lib_prefix) - 1, lib, len);
430 rb_str_set_len(fn, total_len);
431 OBJ_FREEZE(fn);
432 rb_require_internal_silent(fn); // Sets entry->transcoder
433 }
434
435 if (entry->transcoder)
436 return entry->transcoder;
437
438 return NULL;
439}
440
441static const char*
442get_replacement_character(const char *encname, size_t *len_ret, const char **repl_encname_ptr)
443{
444 if (encoding_equal(encname, "UTF-8")) {
445 *len_ret = 3;
446 *repl_encname_ptr = "UTF-8";
447 return "\xEF\xBF\xBD";
448 }
449 else {
450 *len_ret = 1;
451 *repl_encname_ptr = "US-ASCII";
452 return "?";
453 }
454}
455
456/*
457 * Transcoding engine logic
458 */
459
460static const unsigned char *
461transcode_char_start(rb_transcoding *tc,
462 const unsigned char *in_start,
463 const unsigned char *inchar_start,
464 const unsigned char *in_p,
465 size_t *char_len_ptr)
466{
467 const unsigned char *ptr;
468 if (inchar_start - in_start < tc->recognized_len) {
469 MEMCPY(TRANSCODING_READBUF(tc) + tc->recognized_len,
470 inchar_start, unsigned char, in_p - inchar_start);
471 ptr = TRANSCODING_READBUF(tc);
472 }
473 else {
474 ptr = inchar_start - tc->recognized_len;
475 }
476 *char_len_ptr = tc->recognized_len + (in_p - inchar_start);
477 return ptr;
478}
479
481transcode_restartable0(const unsigned char **in_pos, unsigned char **out_pos,
482 const unsigned char *in_stop, unsigned char *out_stop,
483 rb_transcoding *tc,
484 const int opt)
485{
486 const rb_transcoder *tr = tc->transcoder;
487 int unitlen = tr->input_unit_length;
488 ssize_t readagain_len = 0;
489
490 const unsigned char *inchar_start;
491 const unsigned char *in_p;
492
493 unsigned char *out_p;
494
495 in_p = inchar_start = *in_pos;
496
497 out_p = *out_pos;
498
499#define SUSPEND(ret, num) \
500 do { \
501 tc->resume_position = (num); \
502 if (0 < in_p - inchar_start) \
503 MEMMOVE(TRANSCODING_READBUF(tc)+tc->recognized_len, \
504 inchar_start, unsigned char, in_p - inchar_start); \
505 *in_pos = in_p; \
506 *out_pos = out_p; \
507 tc->recognized_len += in_p - inchar_start; \
508 if (readagain_len) { \
509 tc->recognized_len -= readagain_len; \
510 tc->readagain_len = readagain_len; \
511 } \
512 return (ret); \
513 resume_label ## num:; \
514 } while (0)
515#define SUSPEND_OBUF(num) \
516 do { \
517 while (out_stop - out_p < 1) { SUSPEND(econv_destination_buffer_full, num); } \
518 } while (0)
519
520#define SUSPEND_AFTER_OUTPUT(num) \
521 if ((opt & ECONV_AFTER_OUTPUT) && *out_pos != out_p) { \
522 SUSPEND(econv_after_output, num); \
523 }
524
525#define next_table (tc->next_table)
526#define next_info (tc->next_info)
527#define next_byte (tc->next_byte)
528#define writebuf_len (tc->writebuf_len)
529#define writebuf_off (tc->writebuf_off)
530
531 switch (tc->resume_position) {
532 case 0: break;
533 case 1: goto resume_label1;
534 case 2: goto resume_label2;
535 case 3: goto resume_label3;
536 case 4: goto resume_label4;
537 case 5: goto resume_label5;
538 case 6: goto resume_label6;
539 case 7: goto resume_label7;
540 case 8: goto resume_label8;
541 case 9: goto resume_label9;
542 case 10: goto resume_label10;
543 case 11: goto resume_label11;
544 case 12: goto resume_label12;
545 case 13: goto resume_label13;
546 case 14: goto resume_label14;
547 case 15: goto resume_label15;
548 case 16: goto resume_label16;
549 case 17: goto resume_label17;
550 case 18: goto resume_label18;
551 case 19: goto resume_label19;
552 case 20: goto resume_label20;
553 case 21: goto resume_label21;
554 case 22: goto resume_label22;
555 case 23: goto resume_label23;
556 case 24: goto resume_label24;
557 case 25: goto resume_label25;
558 case 26: goto resume_label26;
559 case 27: goto resume_label27;
560 case 28: goto resume_label28;
561 case 29: goto resume_label29;
562 case 30: goto resume_label30;
563 case 31: goto resume_label31;
564 case 32: goto resume_label32;
565 case 33: goto resume_label33;
566 case 34: goto resume_label34;
567 }
568
569 while (1) {
570 inchar_start = in_p;
571 tc->recognized_len = 0;
572 next_table = tr->conv_tree_start;
573
574 SUSPEND_AFTER_OUTPUT(24);
575
576 if (in_stop <= in_p) {
577 if (!(opt & ECONV_PARTIAL_INPUT))
578 break;
579 SUSPEND(econv_source_buffer_empty, 7);
580 continue;
581 }
582
583#define BYTE_ADDR(index) (tr->byte_array + (index))
584#define WORD_ADDR(index) (tr->word_array + INFO2WORDINDEX(index))
585#define BL_BASE BYTE_ADDR(BYTE_LOOKUP_BASE(WORD_ADDR(next_table)))
586#define BL_INFO WORD_ADDR(BYTE_LOOKUP_INFO(WORD_ADDR(next_table)))
587#define BL_MIN_BYTE (BL_BASE[0])
588#define BL_MAX_BYTE (BL_BASE[1])
589#define BL_OFFSET(byte) (BL_BASE[2+(byte)-BL_MIN_BYTE])
590#define BL_ACTION(byte) (BL_INFO[BL_OFFSET((byte))])
591
592 next_byte = (unsigned char)*in_p++;
593 follow_byte:
594 if (next_byte < BL_MIN_BYTE || BL_MAX_BYTE < next_byte)
595 next_info = INVALID;
596 else {
597 next_info = (VALUE)BL_ACTION(next_byte);
598 }
599 follow_info:
600 switch (next_info & 0x1F) {
601 case NOMAP:
602 {
603 const unsigned char *p = inchar_start;
604 writebuf_off = 0;
605 while (p < in_p) {
606 TRANSCODING_WRITEBUF(tc)[writebuf_off++] = (unsigned char)*p++;
607 }
608 writebuf_len = writebuf_off;
609 writebuf_off = 0;
610 while (writebuf_off < writebuf_len) {
611 SUSPEND_OBUF(3);
612 *out_p++ = TRANSCODING_WRITEBUF(tc)[writebuf_off++];
613 }
614 }
615 continue;
616 case 0x00: case 0x04: case 0x08: case 0x0C:
617 case 0x10: case 0x14: case 0x18: case 0x1C:
618 SUSPEND_AFTER_OUTPUT(25);
619 while (in_p >= in_stop) {
620 if (!(opt & ECONV_PARTIAL_INPUT))
621 goto incomplete;
622 SUSPEND(econv_source_buffer_empty, 5);
623 }
624 next_byte = (unsigned char)*in_p++;
625 next_table = (unsigned int)next_info;
626 goto follow_byte;
627 case ZERObt: /* drop input */
628 continue;
629 case ONEbt:
630 SUSPEND_OBUF(9); *out_p++ = getBT1(next_info);
631 continue;
632 case TWObt:
633 SUSPEND_OBUF(10); *out_p++ = getBT1(next_info);
634 SUSPEND_OBUF(21); *out_p++ = getBT2(next_info);
635 continue;
636 case THREEbt:
637 SUSPEND_OBUF(11); *out_p++ = getBT1(next_info);
638 SUSPEND_OBUF(15); *out_p++ = getBT2(next_info);
639 SUSPEND_OBUF(16); *out_p++ = getBT3(next_info);
640 continue;
641 case FOURbt:
642 SUSPEND_OBUF(12); *out_p++ = getBT0(next_info);
643 SUSPEND_OBUF(17); *out_p++ = getBT1(next_info);
644 SUSPEND_OBUF(18); *out_p++ = getBT2(next_info);
645 SUSPEND_OBUF(19); *out_p++ = getBT3(next_info);
646 continue;
647 case GB4bt:
648 SUSPEND_OBUF(29); *out_p++ = getGB4bt0(next_info);
649 SUSPEND_OBUF(30); *out_p++ = getGB4bt1(next_info);
650 SUSPEND_OBUF(31); *out_p++ = getGB4bt2(next_info);
651 SUSPEND_OBUF(32); *out_p++ = getGB4bt3(next_info);
652 continue;
653 case STR1:
654 tc->output_index = 0;
655 while (tc->output_index < STR1_LENGTH(BYTE_ADDR(STR1_BYTEINDEX(next_info)))) {
656 SUSPEND_OBUF(28); *out_p++ = BYTE_ADDR(STR1_BYTEINDEX(next_info))[1+tc->output_index];
657 tc->output_index++;
658 }
659 continue;
660 case FUNii:
661 next_info = (VALUE)(*tr->func_ii)(TRANSCODING_STATE(tc), next_info);
662 goto follow_info;
663 case FUNsi:
664 {
665 const unsigned char *char_start;
666 size_t char_len;
667 char_start = transcode_char_start(tc, *in_pos, inchar_start, in_p, &char_len);
668 next_info = (VALUE)(*tr->func_si)(TRANSCODING_STATE(tc), char_start, (size_t)char_len);
669 goto follow_info;
670 }
671 case FUNio:
672 SUSPEND_OBUF(13);
673 if (tr->max_output <= out_stop - out_p)
674 out_p += tr->func_io(TRANSCODING_STATE(tc),
675 next_info, out_p, out_stop - out_p);
676 else {
677 writebuf_len = tr->func_io(TRANSCODING_STATE(tc),
678 next_info,
679 TRANSCODING_WRITEBUF(tc), TRANSCODING_WRITEBUF_SIZE(tc));
680 writebuf_off = 0;
681 while (writebuf_off < writebuf_len) {
682 SUSPEND_OBUF(20);
683 *out_p++ = TRANSCODING_WRITEBUF(tc)[writebuf_off++];
684 }
685 }
686 break;
687 case FUNso:
688 {
689 const unsigned char *char_start;
690 size_t char_len;
691 SUSPEND_OBUF(14);
692 if (tr->max_output <= out_stop - out_p) {
693 char_start = transcode_char_start(tc, *in_pos, inchar_start, in_p, &char_len);
694 out_p += tr->func_so(TRANSCODING_STATE(tc),
695 char_start, (size_t)char_len,
696 out_p, out_stop - out_p);
697 }
698 else {
699 char_start = transcode_char_start(tc, *in_pos, inchar_start, in_p, &char_len);
700 writebuf_len = tr->func_so(TRANSCODING_STATE(tc),
701 char_start, (size_t)char_len,
702 TRANSCODING_WRITEBUF(tc), TRANSCODING_WRITEBUF_SIZE(tc));
703 writebuf_off = 0;
704 while (writebuf_off < writebuf_len) {
705 SUSPEND_OBUF(22);
706 *out_p++ = TRANSCODING_WRITEBUF(tc)[writebuf_off++];
707 }
708 }
709 break;
710 }
711 case FUNsio:
712 {
713 const unsigned char *char_start;
714 size_t char_len;
715 SUSPEND_OBUF(33);
716 if (tr->max_output <= out_stop - out_p) {
717 char_start = transcode_char_start(tc, *in_pos, inchar_start, in_p, &char_len);
718 out_p += tr->func_sio(TRANSCODING_STATE(tc),
719 char_start, (size_t)char_len, next_info,
720 out_p, out_stop - out_p);
721 }
722 else {
723 char_start = transcode_char_start(tc, *in_pos, inchar_start, in_p, &char_len);
724 writebuf_len = tr->func_sio(TRANSCODING_STATE(tc),
725 char_start, (size_t)char_len, next_info,
726 TRANSCODING_WRITEBUF(tc), TRANSCODING_WRITEBUF_SIZE(tc));
727 writebuf_off = 0;
728 while (writebuf_off < writebuf_len) {
729 SUSPEND_OBUF(34);
730 *out_p++ = TRANSCODING_WRITEBUF(tc)[writebuf_off++];
731 }
732 }
733 break;
734 }
735 case INVALID:
736 if (tc->recognized_len + (in_p - inchar_start) <= unitlen) {
737 if (tc->recognized_len + (in_p - inchar_start) < unitlen)
738 SUSPEND_AFTER_OUTPUT(26);
739 while ((opt & ECONV_PARTIAL_INPUT) && tc->recognized_len + (in_stop - inchar_start) < unitlen) {
740 in_p = in_stop;
741 SUSPEND(econv_source_buffer_empty, 8);
742 }
743 if (tc->recognized_len + (in_stop - inchar_start) <= unitlen) {
744 in_p = in_stop;
745 }
746 else {
747 in_p = inchar_start + (unitlen - tc->recognized_len);
748 }
749 }
750 else {
751 ssize_t invalid_len; /* including the last byte which causes invalid */
752 ssize_t discard_len;
753 invalid_len = tc->recognized_len + (in_p - inchar_start);
754 discard_len = ((invalid_len - 1) / unitlen) * unitlen;
755 readagain_len = invalid_len - discard_len;
756 }
757 goto invalid;
758 case UNDEF:
759 goto undef;
760 default:
761 rb_raise(rb_eRuntimeError, "unknown transcoding instruction");
762 }
763 continue;
764
765 invalid:
766 SUSPEND(econv_invalid_byte_sequence, 1);
767 continue;
768
769 incomplete:
770 SUSPEND(econv_incomplete_input, 27);
771 continue;
772
773 undef:
774 SUSPEND(econv_undefined_conversion, 2);
775 continue;
776 }
777
778 /* cleanup */
779 if (tr->finish_func) {
780 SUSPEND_OBUF(4);
781 if (tr->max_output <= out_stop - out_p) {
782 out_p += tr->finish_func(TRANSCODING_STATE(tc),
783 out_p, out_stop - out_p);
784 }
785 else {
786 writebuf_len = tr->finish_func(TRANSCODING_STATE(tc),
787 TRANSCODING_WRITEBUF(tc), TRANSCODING_WRITEBUF_SIZE(tc));
788 writebuf_off = 0;
789 while (writebuf_off < writebuf_len) {
790 SUSPEND_OBUF(23);
791 *out_p++ = TRANSCODING_WRITEBUF(tc)[writebuf_off++];
792 }
793 }
794 }
795 while (1)
796 SUSPEND(econv_finished, 6);
797#undef SUSPEND
798#undef next_table
799#undef next_info
800#undef next_byte
801#undef writebuf_len
802#undef writebuf_off
803}
804
806transcode_restartable(const unsigned char **in_pos, unsigned char **out_pos,
807 const unsigned char *in_stop, unsigned char *out_stop,
808 rb_transcoding *tc,
809 const int opt)
810{
811 if (tc->readagain_len) {
812 unsigned char *readagain_buf = ALLOCA_N(unsigned char, tc->readagain_len);
813 const unsigned char *readagain_pos = readagain_buf;
814 const unsigned char *readagain_stop = readagain_buf + tc->readagain_len;
816
817 MEMCPY(readagain_buf, TRANSCODING_READBUF(tc) + tc->recognized_len,
818 unsigned char, tc->readagain_len);
819 tc->readagain_len = 0;
820 res = transcode_restartable0(&readagain_pos, out_pos, readagain_stop, out_stop, tc, opt|ECONV_PARTIAL_INPUT);
821 if (res != econv_source_buffer_empty) {
822 MEMCPY(TRANSCODING_READBUF(tc) + tc->recognized_len + tc->readagain_len,
823 readagain_pos, unsigned char, readagain_stop - readagain_pos);
824 tc->readagain_len += readagain_stop - readagain_pos;
825 return res;
826 }
827 }
828 return transcode_restartable0(in_pos, out_pos, in_stop, out_stop, tc, opt);
829}
830
831static rb_transcoding *
832rb_transcoding_open_by_transcoder(const rb_transcoder *tr, int flags)
833{
834 rb_transcoding *tc;
835
836 tc = ALLOC(rb_transcoding);
837 tc->transcoder = tr;
838 tc->flags = flags;
839 if (TRANSCODING_STATE_EMBED_MAX < tr->state_size)
840 tc->state.ptr = xmalloc(tr->state_size);
841 if (tr->state_init_func) {
842 (tr->state_init_func)(TRANSCODING_STATE(tc)); /* xxx: check return value */
843 }
844 tc->resume_position = 0;
845 tc->recognized_len = 0;
846 tc->readagain_len = 0;
847 tc->writebuf_len = 0;
848 tc->writebuf_off = 0;
849 if ((int)sizeof(tc->readbuf.ary) < tr->max_input) {
850 tc->readbuf.ptr = xmalloc(tr->max_input);
851 }
852 if ((int)sizeof(tc->writebuf.ary) < tr->max_output) {
853 tc->writebuf.ptr = xmalloc(tr->max_output);
854 }
855 return tc;
856}
857
859rb_transcoding_convert(rb_transcoding *tc,
860 const unsigned char **input_ptr, const unsigned char *input_stop,
861 unsigned char **output_ptr, unsigned char *output_stop,
862 int flags)
863{
864 return transcode_restartable(
865 input_ptr, output_ptr,
866 input_stop, output_stop,
867 tc, flags);
868}
869
870static void
871rb_transcoding_close(rb_transcoding *tc)
872{
873 const rb_transcoder *tr = tc->transcoder;
874 if (tr->state_fini_func) {
875 (tr->state_fini_func)(TRANSCODING_STATE(tc)); /* check return value? */
876 }
877 if (TRANSCODING_STATE_EMBED_MAX < tr->state_size)
878 ruby_xfree_sized(tc->state.ptr, tr->state_size);
879 if ((int)sizeof(tc->readbuf.ary) < tr->max_input)
880 ruby_xfree_sized(tc->readbuf.ptr, tr->max_input);
881 if ((int)sizeof(tc->writebuf.ary) < tr->max_output)
882 ruby_xfree_sized(tc->writebuf.ptr, tr->max_output);
883 SIZED_FREE(tc);
884}
885
886static size_t
887rb_transcoding_memsize(rb_transcoding *tc)
888{
889 size_t size = sizeof(rb_transcoding);
890 const rb_transcoder *tr = tc->transcoder;
891
892 if (TRANSCODING_STATE_EMBED_MAX < tr->state_size) {
893 size += tr->state_size;
894 }
895 if ((int)sizeof(tc->readbuf.ary) < tr->max_input) {
896 size += tr->max_input;
897 }
898 if ((int)sizeof(tc->writebuf.ary) < tr->max_output) {
899 size += tr->max_output;
900 }
901 return size;
902}
903
904static rb_econv_t *
905rb_econv_alloc(int n_hint)
906{
907 rb_econv_t *ec;
908
909 if (n_hint <= 0)
910 n_hint = 1;
911
912 ec = ALLOC(rb_econv_t);
913 ec->flags = 0;
914 ec->source_encoding_name = NULL;
915 ec->destination_encoding_name = NULL;
916 ec->started = 0;
917 ec->replacement_str = NULL;
918 ec->replacement_len = 0;
919 ec->replacement_bufsize = 0;
920 ec->replacement_enc = NULL;
921 ec->replacement_allocated = 0;
922 ec->in_buf_start = NULL;
923 ec->in_data_start = NULL;
924 ec->in_data_end = NULL;
925 ec->in_buf_end = NULL;
926 ec->num_allocated = n_hint;
927 ec->num_trans = 0;
928 ec->elems = ALLOC_N(rb_econv_elem_t, ec->num_allocated);
929 ec->num_finished = 0;
930 ec->last_tc = NULL;
931 ec->last_error.result = econv_source_buffer_empty;
932 ec->last_error.error_tc = NULL;
933 ec->last_error.source_encoding = NULL;
934 ec->last_error.destination_encoding = NULL;
935 ec->last_error.error_bytes_start = NULL;
936 ec->last_error.error_bytes_len = 0;
937 ec->last_error.readagain_len = 0;
938 ec->source_encoding = NULL;
939 ec->destination_encoding = NULL;
940 return ec;
941}
942
943static int
944rb_econv_add_transcoder_at(rb_econv_t *ec, const rb_transcoder *tr, int i)
945{
946 int n, j;
947 int bufsize = 4096;
948 unsigned char *p;
949
950 if (ec->num_trans == ec->num_allocated) {
951 n = ec->num_allocated * 2;
952 SIZED_REALLOC_N(ec->elems, rb_econv_elem_t, n, ec->num_allocated);
953 ec->num_allocated = n;
954 }
955
956 p = xmalloc(bufsize);
957
958 MEMMOVE(ec->elems+i+1, ec->elems+i, rb_econv_elem_t, ec->num_trans-i);
959
960 ec->elems[i].tc = rb_transcoding_open_by_transcoder(tr, 0);
961 ec->elems[i].out_buf_start = p;
962 ec->elems[i].out_buf_end = p + bufsize;
963 ec->elems[i].out_data_start = p;
964 ec->elems[i].out_data_end = p;
965 ec->elems[i].last_result = econv_source_buffer_empty;
966
967 ec->num_trans++;
968
969 if (!DECORATOR_P(tr->src_encoding, tr->dst_encoding))
970 for (j = ec->num_trans-1; i <= j; j--) {
971 rb_transcoding *tc = ec->elems[j].tc;
972 const rb_transcoder *tr2 = tc->transcoder;
973 if (!DECORATOR_P(tr2->src_encoding, tr2->dst_encoding)) {
974 ec->last_tc = tc;
975 break;
976 }
977 }
978
979 return 0;
980}
981
982static rb_econv_t *
983rb_econv_open_by_transcoder_entries(int n, transcoder_entry_t **entries)
984{
985 rb_econv_t *ec;
986 int i, ret;
987
988 for (i = 0; i < n; i++) {
989 const rb_transcoder *tr;
990 tr = load_transcoder_entry(entries[i]);
991 if (!tr)
992 return NULL;
993 }
994
995 ec = rb_econv_alloc(n);
996
997 for (i = 0; i < n; i++) {
998 const rb_transcoder *tr = load_transcoder_entry(entries[i]);
999 ret = rb_econv_add_transcoder_at(ec, tr, ec->num_trans);
1000 if (ret == -1) {
1001 rb_econv_close(ec);
1002 return NULL;
1003 }
1004 }
1005
1006 return ec;
1007}
1008
1010 transcoder_entry_t **entries;
1011};
1012
1013static void
1014trans_open_i(const char *sname, const char *dname, int depth, void *arg)
1015{
1016 struct trans_open_t *toarg = arg;
1017
1018 if (!toarg->entries) {
1019 toarg->entries = ALLOC_N(transcoder_entry_t *, depth + 1);
1020 }
1021 toarg->entries[depth] = get_transcoder_entry(sname, dname);
1022}
1023
1024static rb_econv_t *
1025rb_econv_open0(const char *sname, const char *dname, int ecflags)
1026{
1027 transcoder_entry_t **entries = NULL;
1028 int num_trans;
1029 rb_econv_t *ec;
1030
1031 // loads encodings if not loaded already
1032 if (*sname) rb_enc_find_index(sname);
1033 if (*dname) rb_enc_find_index(dname);
1034
1035 if (*sname == '\0' && *dname == '\0') {
1036 num_trans = 0;
1037 entries = NULL;
1038 sname = dname = "";
1039 }
1040 else {
1041 struct trans_open_t toarg = {0};
1042 num_trans = transcode_search_path(sname, dname, trans_open_i, (void *)&toarg);
1043 entries = toarg.entries;
1044 if (num_trans < 0) {
1045 SIZED_FREE_N(entries, num_trans);
1046 return NULL;
1047 }
1048 }
1049
1050 ec = rb_econv_open_by_transcoder_entries(num_trans, entries);
1051 SIZED_FREE_N(entries, num_trans);
1052 if (!ec)
1053 return NULL;
1054
1055 ec->flags = ecflags;
1056 ec->source_encoding_name = sname;
1057 ec->destination_encoding_name = dname;
1058
1059 return ec;
1060}
1061
1062#define MAX_ECFLAGS_DECORATORS 32
1063
1064static int
1065decorator_names(int ecflags, const char **decorators_ret)
1066{
1067 int num_decorators;
1068
1069 switch (ecflags & ECONV_NEWLINE_DECORATOR_MASK) {
1074 case 0:
1075 break;
1076 default:
1077 return -1;
1078 }
1079
1080 if ((ecflags & ECONV_XML_TEXT_DECORATOR) &&
1082 return -1;
1083
1084 num_decorators = 0;
1085
1086 if (ecflags & ECONV_XML_TEXT_DECORATOR)
1087 decorators_ret[num_decorators++] = "xml_text_escape";
1089 decorators_ret[num_decorators++] = "xml_attr_content_escape";
1090 if (ecflags & ECONV_XML_ATTR_QUOTE_DECORATOR)
1091 decorators_ret[num_decorators++] = "xml_attr_quote";
1092
1093 if (ecflags & ECONV_CRLF_NEWLINE_DECORATOR)
1094 decorators_ret[num_decorators++] = "crlf_newline";
1095 if (ecflags & ECONV_CR_NEWLINE_DECORATOR)
1096 decorators_ret[num_decorators++] = "cr_newline";
1097 if (ecflags & ECONV_LF_NEWLINE_DECORATOR)
1098 decorators_ret[num_decorators++] = "lf_newline";
1100 decorators_ret[num_decorators++] = "universal_newline";
1101
1102 return num_decorators;
1103}
1104
1105rb_econv_t *
1106rb_econv_open(const char *sname, const char *dname, int ecflags)
1107{
1108 rb_econv_t *ec;
1109 int num_decorators;
1110 const char *decorators[MAX_ECFLAGS_DECORATORS];
1111 int i;
1112
1113 num_decorators = decorator_names(ecflags, decorators);
1114 if (num_decorators == -1)
1115 return NULL;
1116
1117 ec = rb_econv_open0(sname, dname, ecflags & ECONV_ERROR_HANDLER_MASK);
1118 if (ec) {
1119 for (i = 0; i < num_decorators; i++) {
1120 if (rb_econv_decorate_at_last(ec, decorators[i]) == -1) {
1121 rb_econv_close(ec);
1122 ec = NULL;
1123 break;
1124 }
1125 }
1126 }
1127
1128 if (ec) {
1129 ec->flags |= ecflags & ~ECONV_ERROR_HANDLER_MASK;
1130 }
1131 return ec; // can be NULL
1132}
1133
1134static int
1135trans_sweep(rb_econv_t *ec,
1136 const unsigned char **input_ptr, const unsigned char *input_stop,
1137 unsigned char **output_ptr, unsigned char *output_stop,
1138 int flags,
1139 int start)
1140{
1141 int try;
1142 int i, f;
1143
1144 const unsigned char **ipp, *is, *iold;
1145 unsigned char **opp, *os, *oold;
1147
1148 try = 1;
1149 while (try) {
1150 try = 0;
1151 for (i = start; i < ec->num_trans; i++) {
1152 rb_econv_elem_t *te = &ec->elems[i];
1153
1154 if (i == 0) {
1155 ipp = input_ptr;
1156 is = input_stop;
1157 }
1158 else {
1159 rb_econv_elem_t *prev_te = &ec->elems[i-1];
1160 ipp = (const unsigned char **)&prev_te->out_data_start;
1161 is = prev_te->out_data_end;
1162 }
1163
1164 if (i == ec->num_trans-1) {
1165 opp = output_ptr;
1166 os = output_stop;
1167 }
1168 else {
1169 if (te->out_buf_start != te->out_data_start) {
1170 ssize_t len = te->out_data_end - te->out_data_start;
1171 ssize_t off = te->out_data_start - te->out_buf_start;
1172 MEMMOVE(te->out_buf_start, te->out_data_start, unsigned char, len);
1173 te->out_data_start = te->out_buf_start;
1174 te->out_data_end -= off;
1175 }
1176 opp = &te->out_data_end;
1177 os = te->out_buf_end;
1178 }
1179
1180 f = flags;
1181 if (ec->num_finished != i)
1183 if (i == 0 && (flags & ECONV_AFTER_OUTPUT)) {
1184 start = 1;
1185 flags &= ~ECONV_AFTER_OUTPUT;
1186 }
1187 if (i != 0)
1188 f &= ~ECONV_AFTER_OUTPUT;
1189 iold = *ipp;
1190 oold = *opp;
1191 te->last_result = res = rb_transcoding_convert(te->tc, ipp, is, opp, os, f);
1192 if (iold != *ipp || oold != *opp)
1193 try = 1;
1194
1195 switch (res) {
1199 case econv_after_output:
1200 return i;
1201
1204 break;
1205
1206 case econv_finished:
1207 ec->num_finished = i+1;
1208 break;
1209 }
1210 }
1211 }
1212 return -1;
1213}
1214
1215static rb_econv_result_t
1216rb_trans_conv(rb_econv_t *ec,
1217 const unsigned char **input_ptr, const unsigned char *input_stop,
1218 unsigned char **output_ptr, unsigned char *output_stop,
1219 int flags,
1220 int *result_position_ptr)
1221{
1222 int i;
1223 int needreport_index;
1224 int sweep_start;
1225
1226 unsigned char empty_buf;
1227 unsigned char *empty_ptr = &empty_buf;
1228
1229 if (!input_ptr) {
1230 input_ptr = (const unsigned char **)&empty_ptr;
1231 input_stop = empty_ptr;
1232 }
1233
1234 if (!output_ptr) {
1235 output_ptr = &empty_ptr;
1236 output_stop = empty_ptr;
1237 }
1238
1239 if (ec->elems[0].last_result == econv_after_output)
1240 ec->elems[0].last_result = econv_source_buffer_empty;
1241
1242 for (i = ec->num_trans-1; 0 <= i; i--) {
1243 switch (ec->elems[i].last_result) {
1247 case econv_after_output:
1248 case econv_finished:
1249 sweep_start = i+1;
1250 goto found_needreport;
1251
1254 break;
1255
1256 default:
1257 rb_bug("unexpected transcode last result");
1258 }
1259 }
1260
1261 /* /^[sd]+$/ is confirmed. but actually /^s*d*$/. */
1262
1263 if (ec->elems[ec->num_trans-1].last_result == econv_destination_buffer_full &&
1264 (flags & ECONV_AFTER_OUTPUT)) {
1266
1267 res = rb_trans_conv(ec, NULL, NULL, output_ptr, output_stop,
1269 result_position_ptr);
1270
1271 if (res == econv_source_buffer_empty)
1272 return econv_after_output;
1273 return res;
1274 }
1275
1276 sweep_start = 0;
1277
1278 found_needreport:
1279
1280 do {
1281 needreport_index = trans_sweep(ec, input_ptr, input_stop, output_ptr, output_stop, flags, sweep_start);
1282 sweep_start = needreport_index + 1;
1283 } while (needreport_index != -1 && needreport_index != ec->num_trans-1);
1284
1285 for (i = ec->num_trans-1; 0 <= i; i--) {
1286 if (ec->elems[i].last_result != econv_source_buffer_empty) {
1287 rb_econv_result_t res = ec->elems[i].last_result;
1288 if (res == econv_invalid_byte_sequence ||
1289 res == econv_incomplete_input ||
1291 res == econv_after_output) {
1292 ec->elems[i].last_result = econv_source_buffer_empty;
1293 }
1294 if (result_position_ptr)
1295 *result_position_ptr = i;
1296 return res;
1297 }
1298 }
1299 if (result_position_ptr)
1300 *result_position_ptr = -1;
1302}
1303
1304static rb_econv_result_t
1305rb_econv_convert0(rb_econv_t *ec,
1306 const unsigned char **input_ptr, const unsigned char *input_stop,
1307 unsigned char **output_ptr, unsigned char *output_stop,
1308 int flags)
1309{
1311 int result_position;
1312 int has_output = 0;
1313
1314 memset(&ec->last_error, 0, sizeof(ec->last_error));
1315
1316 if (ec->num_trans == 0) {
1317 size_t len;
1318 if (ec->in_buf_start && ec->in_data_start != ec->in_data_end) {
1319 if (output_stop - *output_ptr < ec->in_data_end - ec->in_data_start) {
1320 len = output_stop - *output_ptr;
1321 memcpy(*output_ptr, ec->in_data_start, len);
1322 *output_ptr = output_stop;
1323 ec->in_data_start += len;
1325 goto gotresult;
1326 }
1327 len = ec->in_data_end - ec->in_data_start;
1328 memcpy(*output_ptr, ec->in_data_start, len);
1329 *output_ptr += len;
1330 ec->in_data_start = ec->in_data_end = ec->in_buf_start;
1331 if (flags & ECONV_AFTER_OUTPUT) {
1332 res = econv_after_output;
1333 goto gotresult;
1334 }
1335 }
1336 if (output_stop - *output_ptr < input_stop - *input_ptr) {
1337 len = output_stop - *output_ptr;
1338 }
1339 else {
1340 len = input_stop - *input_ptr;
1341 }
1342 if (0 < len && (flags & ECONV_AFTER_OUTPUT)) {
1343 *(*output_ptr)++ = *(*input_ptr)++;
1344 res = econv_after_output;
1345 goto gotresult;
1346 }
1347 memcpy(*output_ptr, *input_ptr, len);
1348 *output_ptr += len;
1349 *input_ptr += len;
1350 if (*input_ptr != input_stop)
1352 else if (flags & ECONV_PARTIAL_INPUT)
1354 else
1355 res = econv_finished;
1356 goto gotresult;
1357 }
1358
1359 if (ec->elems[ec->num_trans-1].out_data_start) {
1360 unsigned char *data_start = ec->elems[ec->num_trans-1].out_data_start;
1361 unsigned char *data_end = ec->elems[ec->num_trans-1].out_data_end;
1362 if (data_start != data_end) {
1363 size_t len;
1364 if (output_stop - *output_ptr < data_end - data_start) {
1365 len = output_stop - *output_ptr;
1366 memcpy(*output_ptr, data_start, len);
1367 *output_ptr = output_stop;
1368 ec->elems[ec->num_trans-1].out_data_start += len;
1370 goto gotresult;
1371 }
1372 len = data_end - data_start;
1373 memcpy(*output_ptr, data_start, len);
1374 *output_ptr += len;
1375 ec->elems[ec->num_trans-1].out_data_start =
1376 ec->elems[ec->num_trans-1].out_data_end =
1377 ec->elems[ec->num_trans-1].out_buf_start;
1378 has_output = 1;
1379 }
1380 }
1381
1382 if (ec->in_buf_start &&
1383 ec->in_data_start != ec->in_data_end) {
1384 res = rb_trans_conv(ec, (const unsigned char **)&ec->in_data_start, ec->in_data_end, output_ptr, output_stop,
1385 (flags&~ECONV_AFTER_OUTPUT)|ECONV_PARTIAL_INPUT, &result_position);
1386 if (res != econv_source_buffer_empty)
1387 goto gotresult;
1388 }
1389
1390 if (has_output &&
1391 (flags & ECONV_AFTER_OUTPUT) &&
1392 *input_ptr != input_stop) {
1393 input_stop = *input_ptr;
1394 res = rb_trans_conv(ec, input_ptr, input_stop, output_ptr, output_stop, flags, &result_position);
1395 if (res == econv_source_buffer_empty)
1396 res = econv_after_output;
1397 }
1398 else if ((flags & ECONV_AFTER_OUTPUT) ||
1399 ec->num_trans == 1) {
1400 res = rb_trans_conv(ec, input_ptr, input_stop, output_ptr, output_stop, flags, &result_position);
1401 }
1402 else {
1403 flags |= ECONV_AFTER_OUTPUT;
1404 do {
1405 res = rb_trans_conv(ec, input_ptr, input_stop, output_ptr, output_stop, flags, &result_position);
1406 } while (res == econv_after_output);
1407 }
1408
1409 gotresult:
1410 ec->last_error.result = res;
1411 if (res == econv_invalid_byte_sequence ||
1412 res == econv_incomplete_input ||
1414 rb_transcoding *error_tc = ec->elems[result_position].tc;
1415 ec->last_error.error_tc = error_tc;
1416 ec->last_error.source_encoding = error_tc->transcoder->src_encoding;
1417 ec->last_error.destination_encoding = error_tc->transcoder->dst_encoding;
1418 ec->last_error.error_bytes_start = TRANSCODING_READBUF(error_tc);
1419 ec->last_error.error_bytes_len = error_tc->recognized_len;
1420 ec->last_error.readagain_len = error_tc->readagain_len;
1421 }
1422
1423 return res;
1424}
1425
1426static int output_replacement_character(rb_econv_t *ec);
1427
1428static int
1429output_hex_charref(rb_econv_t *ec)
1430{
1431 int ret;
1432 unsigned char utfbuf[1024];
1433 const unsigned char *utf;
1434 size_t utf_len, utf_bufsize;
1435 int utf_allocated = 0;
1436 char charef_buf[16];
1437 const unsigned char *p;
1438
1439 if (encoding_equal(ec->last_error.source_encoding, "UTF-32BE")) {
1440 utf = ec->last_error.error_bytes_start;
1441 utf_len = ec->last_error.error_bytes_len;
1442 }
1443 else {
1444 utf = allocate_converted_string(ec->last_error.source_encoding, "UTF-32BE",
1445 ec->last_error.error_bytes_start, ec->last_error.error_bytes_len,
1446 utfbuf, sizeof(utfbuf),
1447 &utf_len, &utf_bufsize);
1448 if (!utf)
1449 return -1;
1450 if (utf != utfbuf && utf != ec->last_error.error_bytes_start)
1451 utf_allocated = 1;
1452 }
1453
1454 if (utf_len % 4 != 0)
1455 goto fail;
1456
1457 p = utf;
1458 while (4 <= utf_len) {
1459 unsigned int u = 0;
1460 u += p[0] << 24;
1461 u += p[1] << 16;
1462 u += p[2] << 8;
1463 u += p[3];
1464 snprintf(charef_buf, sizeof(charef_buf), "&#x%X;", u);
1465
1466 ret = rb_econv_insert_output(ec, (unsigned char *)charef_buf, strlen(charef_buf), "US-ASCII");
1467 if (ret == -1)
1468 goto fail;
1469
1470 p += 4;
1471 utf_len -= 4;
1472 }
1473
1474 if (utf_allocated)
1475 ruby_xfree_sized((void *)utf, utf_bufsize);
1476 return 0;
1477
1478 fail:
1479 if (utf_allocated)
1480 ruby_xfree_sized((void *)utf, utf_bufsize);
1481 return -1;
1482}
1483
1486 const unsigned char **input_ptr, const unsigned char *input_stop,
1487 unsigned char **output_ptr, unsigned char *output_stop,
1488 int flags)
1489{
1491
1492 unsigned char empty_buf;
1493 unsigned char *empty_ptr = &empty_buf;
1494
1495 ec->started = 1;
1496
1497 if (!input_ptr) {
1498 input_ptr = (const unsigned char **)&empty_ptr;
1499 input_stop = empty_ptr;
1500 }
1501
1502 if (!output_ptr) {
1503 output_ptr = &empty_ptr;
1504 output_stop = empty_ptr;
1505 }
1506
1507 resume:
1508 ret = rb_econv_convert0(ec, input_ptr, input_stop, output_ptr, output_stop, flags);
1509
1510 if (ret == econv_invalid_byte_sequence ||
1511 ret == econv_incomplete_input) {
1512 /* deal with invalid byte sequence */
1513 /* todo: add more alternative behaviors */
1514 switch (ec->flags & ECONV_INVALID_MASK) {
1516 if (output_replacement_character(ec) == 0)
1517 goto resume;
1518 }
1519 }
1520
1521 if (ret == econv_undefined_conversion) {
1522 /* valid character in source encoding
1523 * but no related character(s) in destination encoding */
1524 /* todo: add more alternative behaviors */
1525 switch (ec->flags & ECONV_UNDEF_MASK) {
1527 if (output_replacement_character(ec) == 0)
1528 goto resume;
1529 break;
1530
1532 if (output_hex_charref(ec) == 0)
1533 goto resume;
1534 break;
1535 }
1536 }
1537
1538 return ret;
1539}
1540
1541const char *
1543{
1544 rb_transcoding *tc = ec->last_tc;
1545 const rb_transcoder *tr;
1546
1547 if (tc == NULL)
1548 return "";
1549
1550 tr = tc->transcoder;
1551
1552 if (tr->asciicompat_type == asciicompat_encoder)
1553 return tr->src_encoding;
1554 return tr->dst_encoding;
1555}
1556
1557static unsigned char *
1558allocate_converted_string(const char *sname, const char *dname,
1559 const unsigned char *str, size_t len,
1560 unsigned char *caller_dst_buf, size_t caller_dst_bufsize,
1561 size_t *dst_len_ptr, size_t *dst_bufsize_ptr)
1562{
1563 unsigned char *dst_str;
1564 size_t dst_len;
1565 size_t dst_bufsize;
1566
1567 rb_econv_t *ec;
1569
1570 const unsigned char *sp;
1571 unsigned char *dp;
1572
1573 if (caller_dst_buf)
1574 dst_bufsize = caller_dst_bufsize;
1575 else if (len == 0)
1576 dst_bufsize = 1;
1577 else
1578 dst_bufsize = len;
1579
1580 ec = rb_econv_open(sname, dname, 0);
1581 if (ec == NULL)
1582 return NULL;
1583 if (caller_dst_buf)
1584 dst_str = caller_dst_buf;
1585 else
1586 dst_str = xmalloc(dst_bufsize);
1587 dst_len = 0;
1588 sp = str;
1589 dp = dst_str+dst_len;
1590 res = rb_econv_convert(ec, &sp, str+len, &dp, dst_str+dst_bufsize, 0);
1591 dst_len = dp - dst_str;
1592 while (res == econv_destination_buffer_full) {
1593 if (SIZE_MAX/2 < dst_bufsize) {
1594 goto fail;
1595 }
1596 dst_bufsize *= 2;
1597 if (dst_str == caller_dst_buf) {
1598 unsigned char *tmp;
1599 tmp = xmalloc(dst_bufsize);
1600 memcpy(tmp, dst_str, dst_bufsize/2);
1601 dst_str = tmp;
1602 }
1603 else {
1604 dst_str = ruby_xrealloc_sized(dst_str, dst_bufsize, dst_bufsize / 2);
1605 }
1606 dp = dst_str+dst_len;
1607 res = rb_econv_convert(ec, &sp, str+len, &dp, dst_str+dst_bufsize, 0);
1608 dst_len = dp - dst_str;
1609 }
1610 if (res != econv_finished) {
1611 goto fail;
1612 }
1613 rb_econv_close(ec);
1614 *dst_len_ptr = dst_len;
1615 *dst_bufsize_ptr = dst_bufsize;
1616 return dst_str;
1617
1618 fail:
1619 if (dst_str != caller_dst_buf)
1620 ruby_xfree_sized(dst_str, dst_bufsize);
1621 rb_econv_close(ec);
1622 return NULL;
1623}
1624
1625/* result: 0:success -1:failure */
1626int
1628 const unsigned char *str, size_t len, const char *str_encoding)
1629{
1630 const char *insert_encoding = rb_econv_encoding_to_insert_output(ec);
1631 unsigned char insert_buf[4096];
1632 const unsigned char *insert_str = NULL;
1633 size_t insert_len, insert_bufsize;
1634
1635 int last_trans_index;
1636 rb_transcoding *tc;
1637
1638 unsigned char **buf_start_p;
1639 unsigned char **data_start_p;
1640 unsigned char **data_end_p;
1641 unsigned char **buf_end_p;
1642
1643 size_t need;
1644
1645 ec->started = 1;
1646
1647 if (len == 0)
1648 return 0;
1649
1650 if (encoding_equal(insert_encoding, str_encoding)) {
1651 insert_str = str;
1652 insert_len = len;
1653 }
1654 else {
1655 insert_str = allocate_converted_string(str_encoding, insert_encoding,
1656 str, len, insert_buf, sizeof(insert_buf), &insert_len, &insert_bufsize);
1657 if (insert_str == NULL)
1658 return -1;
1659 }
1660
1661 need = insert_len;
1662
1663 last_trans_index = ec->num_trans-1;
1664 if (ec->num_trans == 0) {
1665 tc = NULL;
1666 buf_start_p = &ec->in_buf_start;
1667 data_start_p = &ec->in_data_start;
1668 data_end_p = &ec->in_data_end;
1669 buf_end_p = &ec->in_buf_end;
1670 }
1671 else if (ec->elems[last_trans_index].tc->transcoder->asciicompat_type == asciicompat_encoder) {
1672 tc = ec->elems[last_trans_index].tc;
1673 need += tc->readagain_len;
1674 if (need < insert_len)
1675 goto fail;
1676 if (last_trans_index == 0) {
1677 buf_start_p = &ec->in_buf_start;
1678 data_start_p = &ec->in_data_start;
1679 data_end_p = &ec->in_data_end;
1680 buf_end_p = &ec->in_buf_end;
1681 }
1682 else {
1683 rb_econv_elem_t *ee = &ec->elems[last_trans_index-1];
1684 buf_start_p = &ee->out_buf_start;
1685 data_start_p = &ee->out_data_start;
1686 data_end_p = &ee->out_data_end;
1687 buf_end_p = &ee->out_buf_end;
1688 }
1689 }
1690 else {
1691 rb_econv_elem_t *ee = &ec->elems[last_trans_index];
1692 buf_start_p = &ee->out_buf_start;
1693 data_start_p = &ee->out_data_start;
1694 data_end_p = &ee->out_data_end;
1695 buf_end_p = &ee->out_buf_end;
1696 tc = ec->elems[last_trans_index].tc;
1697 }
1698
1699 if (*buf_start_p == NULL) {
1700 unsigned char *buf = xmalloc(need);
1701 *buf_start_p = buf;
1702 *data_start_p = buf;
1703 *data_end_p = buf;
1704 *buf_end_p = buf+need;
1705 }
1706 else if ((size_t)(*buf_end_p - *data_end_p) < need) {
1707 MEMMOVE(*buf_start_p, *data_start_p, unsigned char, *data_end_p - *data_start_p);
1708 *data_end_p = *buf_start_p + (*data_end_p - *data_start_p);
1709 *data_start_p = *buf_start_p;
1710 if ((size_t)(*buf_end_p - *data_end_p) < need) {
1711 unsigned char *buf;
1712 size_t s = (*data_end_p - *buf_start_p) + need;
1713 if (s < need)
1714 goto fail;
1715 buf = ruby_xrealloc_sized(*buf_start_p, s, *buf_end_p - *buf_start_p);
1716 *data_start_p = buf;
1717 *data_end_p = buf + (*data_end_p - *buf_start_p);
1718 *buf_start_p = buf;
1719 *buf_end_p = buf + s;
1720 }
1721 }
1722
1723 memcpy(*data_end_p, insert_str, insert_len);
1724 *data_end_p += insert_len;
1725 if (tc && tc->transcoder->asciicompat_type == asciicompat_encoder) {
1726 memcpy(*data_end_p, TRANSCODING_READBUF(tc)+tc->recognized_len, tc->readagain_len);
1727 *data_end_p += tc->readagain_len;
1728 tc->readagain_len = 0;
1729 }
1730
1731 if (insert_str != str && insert_str != insert_buf)
1732 ruby_xfree_sized((void *)insert_str, insert_bufsize);
1733 return 0;
1734
1735 fail:
1736 if (insert_str != str && insert_str != insert_buf)
1737 ruby_xfree_sized((void *)insert_str, insert_bufsize);
1738 return -1;
1739}
1740
1741void
1743{
1744 int i;
1745
1746 if (ec->replacement_allocated) {
1747 SIZED_FREE_N((char *)ec->replacement_str, ec->replacement_bufsize);
1748 }
1749 for (i = 0; i < ec->num_trans; i++) {
1750 rb_transcoding_close(ec->elems[i].tc);
1751 ruby_xfree_sized(ec->elems[i].out_buf_start, ec->elems[i].out_buf_end - ec->elems[i].out_buf_start);
1752 }
1753 SIZED_FREE_N(ec->in_buf_start, ec->in_buf_end - ec->in_buf_start);
1754 SIZED_FREE_N(ec->elems, ec->num_allocated);
1755 SIZED_FREE(ec);
1756}
1757
1758size_t
1759rb_econv_memsize(rb_econv_t *ec)
1760{
1761 size_t size = sizeof(rb_econv_t);
1762 int i;
1763
1764 if (ec->replacement_allocated) {
1765 size += ec->replacement_len;
1766 }
1767 for (i = 0; i < ec->num_trans; i++) {
1768 size += rb_transcoding_memsize(ec->elems[i].tc);
1769
1770 if (ec->elems[i].out_buf_start) {
1771 size += ec->elems[i].out_buf_end - ec->elems[i].out_buf_start;
1772 }
1773 }
1774 size += ec->in_buf_end - ec->in_buf_start;
1775 size += sizeof(rb_econv_elem_t) * ec->num_allocated;
1776
1777 return size;
1778}
1779
1780int
1782{
1783 if (ec->num_trans == 0)
1784 return 0;
1785#if SIZEOF_SIZE_T > SIZEOF_INT
1786 if (ec->elems[0].tc->readagain_len > INT_MAX) return INT_MAX;
1787#endif
1788 return (int)ec->elems[0].tc->readagain_len;
1789}
1790
1791void
1792rb_econv_putback(rb_econv_t *ec, unsigned char *p, int n)
1793{
1794 rb_transcoding *tc;
1795 if (ec->num_trans == 0 || n == 0)
1796 return;
1797 tc = ec->elems[0].tc;
1798 memcpy(p, TRANSCODING_READBUF(tc) + tc->recognized_len + tc->readagain_len - n, n);
1799 tc->readagain_len -= n;
1800}
1801
1803 const char *ascii_compat_name;
1804 const char *ascii_incompat_name;
1805};
1806
1807static int
1808asciicompat_encoding_i(st_data_t key, st_data_t val, st_data_t arg)
1809{
1810 struct asciicompat_encoding_t *data = (struct asciicompat_encoding_t *)arg;
1811 transcoder_entry_t *entry = (transcoder_entry_t *)val;
1812 const rb_transcoder *tr;
1813
1814 if (DECORATOR_P(entry->sname, entry->dname))
1815 return ST_CONTINUE;
1816 tr = load_transcoder_entry(entry);
1817 if (tr && tr->asciicompat_type == asciicompat_decoder) {
1818 data->ascii_compat_name = tr->dst_encoding;
1819 return ST_STOP;
1820 }
1821 return ST_CONTINUE;
1822}
1823
1824const char *
1825rb_econv_asciicompat_encoding(const char *ascii_incompat_name)
1826{
1827 st_data_t v;
1828 st_table *table2;
1829 struct asciicompat_encoding_t data = {0};
1830
1831 unsigned int lev;
1832 RB_VM_LOCK_ENTER_LEV(&lev);
1833 {
1834 if (st_lookup(transcoder_table, (st_data_t)ascii_incompat_name, &v)) {
1835 table2 = (st_table *)v;
1836 /*
1837 * Assumption:
1838 * There is at most one transcoder for
1839 * converting from ASCII incompatible encoding.
1840 *
1841 * For ISO-2022-JP, there is ISO-2022-JP -> stateless-ISO-2022-JP and no others.
1842 */
1843 if (table2->num_entries == 1) {
1844 data.ascii_incompat_name = ascii_incompat_name;
1845 data.ascii_compat_name = NULL;
1846 if (rb_multi_ractor_p()) {
1847 /*
1848 * We need to unlock in case `load_transcoder_entry` actually loads the encoding
1849 * and table2 could be inserted into when we unlock.
1850 */
1851 st_table *dup_table2 = st_copy(table2);
1852 RB_VM_LOCK_LEAVE_LEV(&lev);
1853 st_foreach(dup_table2, asciicompat_encoding_i, (st_data_t)&data);
1854 st_free_table(dup_table2);
1855 RB_VM_LOCK_ENTER_LEV(&lev);
1856 }
1857 else {
1858 st_foreach(table2, asciicompat_encoding_i, (st_data_t)&data);
1859 }
1860 }
1861
1862 }
1863 }
1864 RB_VM_LOCK_LEAVE_LEV(&lev);
1865
1866 return data.ascii_compat_name; // can be NULL
1867}
1868
1869/*
1870 * Append `len` bytes pointed by `ss` to `dst` with converting with `ec`.
1871 *
1872 * If the result of the conversion is not compatible with the encoding of
1873 * `dst`, `dst` may not be valid encoding.
1874 */
1875VALUE
1876rb_econv_append(rb_econv_t *ec, const char *ss, long len, VALUE dst, int flags)
1877{
1878 unsigned const char *sp, *se;
1879 unsigned char *ds, *dp, *de;
1881 int max_output;
1882 enum ruby_coderange_type coderange;
1883 rb_encoding *dst_enc = ec->destination_encoding;
1884
1885 if (NIL_P(dst)) {
1886 dst = rb_str_buf_new(len);
1887 if (dst_enc) {
1888 rb_enc_associate(dst, dst_enc);
1889 }
1890 coderange = ENC_CODERANGE_7BIT; // scan from the start
1891 }
1892 else {
1893 dst_enc = rb_enc_get(dst);
1894 coderange = rb_enc_str_coderange(dst);
1895 }
1896
1897 if (ec->last_tc)
1898 max_output = ec->last_tc->transcoder->max_output;
1899 else
1900 max_output = 1;
1901
1902 do {
1903 int cr;
1904 long dlen = RSTRING_LEN(dst);
1905 if (rb_str_capacity(dst) - dlen < (size_t)len + max_output) {
1906 unsigned long new_capa = (unsigned long)dlen + len + max_output;
1907 if (LONG_MAX < new_capa)
1908 rb_raise(rb_eArgError, "too long string");
1909 rb_str_modify_expand(dst, new_capa - dlen);
1910 }
1911 sp = (const unsigned char *)ss;
1912 se = sp + len;
1913 ds = (unsigned char *)RSTRING_PTR(dst);
1914 de = ds + rb_str_capacity(dst);
1915 dp = ds += dlen;
1916 res = rb_econv_convert(ec, &sp, se, &dp, de, flags);
1917 switch (coderange) {
1918 case ENC_CODERANGE_7BIT:
1920 cr = (int)coderange;
1921 rb_str_coderange_scan_restartable((char *)ds, (char *)dp, dst_enc, &cr);
1922 coderange = cr;
1923 ENC_CODERANGE_SET(dst, coderange);
1924 break;
1927 break;
1928 }
1929 len -= (const char *)sp - ss;
1930 ss = (const char *)sp;
1931 rb_str_set_len(dst, dlen + (dp - ds));
1933 } while (res == econv_destination_buffer_full);
1934
1935 return dst;
1936}
1937
1938VALUE
1939rb_econv_substr_append(rb_econv_t *ec, VALUE src, long off, long len, VALUE dst, int flags)
1940{
1941 src = rb_str_new_frozen(src);
1942 dst = rb_econv_append(ec, RSTRING_PTR(src) + off, len, dst, flags);
1943 RB_GC_GUARD(src);
1944 return dst;
1945}
1946
1947VALUE
1949{
1950 return rb_econv_substr_append(ec, src, 0, RSTRING_LEN(src), dst, flags);
1951}
1952
1953VALUE
1954rb_econv_substr_convert(rb_econv_t *ec, VALUE src, long byteoff, long bytesize, int flags)
1955{
1956 return rb_econv_substr_append(ec, src, byteoff, bytesize, Qnil, flags);
1957}
1958
1959VALUE
1961{
1962 return rb_econv_substr_append(ec, src, 0, RSTRING_LEN(src), Qnil, flags);
1963}
1964
1965static int
1966rb_econv_add_converter(rb_econv_t *ec, const char *sname, const char *dname, int n)
1967{
1968 transcoder_entry_t *entry;
1969 const rb_transcoder *tr = NULL;
1970
1971 if (ec->started != 0)
1972 return -1;
1973
1974 entry = get_transcoder_entry(sname, dname);
1975 if (entry) {
1976 tr = load_transcoder_entry(entry);
1977 }
1978
1979 return tr ? rb_econv_add_transcoder_at(ec, tr, n) : -1;
1980}
1981
1982static int
1983rb_econv_decorate_at(rb_econv_t *ec, const char *decorator_name, int n)
1984{
1985 return rb_econv_add_converter(ec, "", decorator_name, n);
1986}
1987
1988int
1989rb_econv_decorate_at_first(rb_econv_t *ec, const char *decorator_name)
1990{
1991 const rb_transcoder *tr;
1992
1993 if (ec->num_trans == 0)
1994 return rb_econv_decorate_at(ec, decorator_name, 0);
1995
1996 tr = ec->elems[0].tc->transcoder;
1997
1998 if (!DECORATOR_P(tr->src_encoding, tr->dst_encoding) &&
1999 tr->asciicompat_type == asciicompat_decoder)
2000 return rb_econv_decorate_at(ec, decorator_name, 1);
2001
2002 return rb_econv_decorate_at(ec, decorator_name, 0);
2003}
2004
2005int
2006rb_econv_decorate_at_last(rb_econv_t *ec, const char *decorator_name)
2007{
2008 const rb_transcoder *tr;
2009
2010 if (ec->num_trans == 0)
2011 return rb_econv_decorate_at(ec, decorator_name, 0);
2012
2013 tr = ec->elems[ec->num_trans-1].tc->transcoder;
2014
2015 if (!DECORATOR_P(tr->src_encoding, tr->dst_encoding) &&
2016 tr->asciicompat_type == asciicompat_encoder)
2017 return rb_econv_decorate_at(ec, decorator_name, ec->num_trans-1);
2018
2019 return rb_econv_decorate_at(ec, decorator_name, ec->num_trans);
2020}
2021
2022void
2024{
2025 const char *dname = 0;
2026
2027 switch (ec->flags & ECONV_NEWLINE_DECORATOR_MASK) {
2029 dname = "universal_newline";
2030 break;
2032 dname = "crlf_newline";
2033 break;
2035 dname = "cr_newline";
2036 break;
2038 dname = "lf_newline";
2039 break;
2040 }
2041
2042 if (dname) {
2043 const rb_transcoder *transcoder = get_transcoder_entry("", dname)->transcoder;
2044 int num_trans = ec->num_trans;
2045 int i, j = 0;
2046
2047 for (i=0; i < num_trans; i++) {
2048 if (transcoder == ec->elems[i].tc->transcoder) {
2049 rb_transcoding_close(ec->elems[i].tc);
2050 ruby_xfree_sized(ec->elems[i].out_buf_start, ec->elems[i].out_buf_end - ec->elems[i].out_buf_start);
2051 ec->num_trans--;
2052 }
2053 else
2054 ec->elems[j++] = ec->elems[i];
2055 }
2056 }
2057
2058 ec->flags &= ~ECONV_NEWLINE_DECORATOR_MASK;
2059}
2060
2061static VALUE
2062econv_description(const char *sname, const char *dname, int ecflags, VALUE mesg)
2063{
2064 int has_description = 0;
2065
2066 if (NIL_P(mesg))
2067 mesg = rb_str_new(NULL, 0);
2068
2069 if (*sname != '\0' || *dname != '\0') {
2070 if (*sname == '\0')
2071 rb_str_cat2(mesg, dname);
2072 else if (*dname == '\0')
2073 rb_str_cat2(mesg, sname);
2074 else
2075 rb_str_catf(mesg, "%s to %s", sname, dname);
2076 has_description = 1;
2077 }
2078
2079 if (ecflags & (ECONV_NEWLINE_DECORATOR_MASK|
2083 const char *pre = "";
2084 if (has_description)
2085 rb_str_cat2(mesg, " with ");
2086 if (ecflags & ECONV_UNIVERSAL_NEWLINE_DECORATOR) {
2087 rb_str_cat2(mesg, pre); pre = ",";
2088 rb_str_cat2(mesg, "universal_newline");
2089 }
2090 if (ecflags & ECONV_CRLF_NEWLINE_DECORATOR) {
2091 rb_str_cat2(mesg, pre); pre = ",";
2092 rb_str_cat2(mesg, "crlf_newline");
2093 }
2094 if (ecflags & ECONV_CR_NEWLINE_DECORATOR) {
2095 rb_str_cat2(mesg, pre); pre = ",";
2096 rb_str_cat2(mesg, "cr_newline");
2097 }
2098 if (ecflags & ECONV_LF_NEWLINE_DECORATOR) {
2099 rb_str_cat2(mesg, pre); pre = ",";
2100 rb_str_cat2(mesg, "lf_newline");
2101 }
2102 if (ecflags & ECONV_XML_TEXT_DECORATOR) {
2103 rb_str_cat2(mesg, pre); pre = ",";
2104 rb_str_cat2(mesg, "xml_text");
2105 }
2106 if (ecflags & ECONV_XML_ATTR_CONTENT_DECORATOR) {
2107 rb_str_cat2(mesg, pre); pre = ",";
2108 rb_str_cat2(mesg, "xml_attr_content");
2109 }
2110 if (ecflags & ECONV_XML_ATTR_QUOTE_DECORATOR) {
2111 rb_str_cat2(mesg, pre); pre = ",";
2112 rb_str_cat2(mesg, "xml_attr_quote");
2113 }
2114 has_description = 1;
2115 }
2116 if (!has_description) {
2117 rb_str_cat2(mesg, "no-conversion");
2118 }
2119
2120 return mesg;
2121}
2122
2123VALUE
2124rb_econv_open_exc(const char *sname, const char *dname, int ecflags)
2125{
2126 VALUE mesg, exc;
2127 mesg = rb_str_new_cstr("code converter not found (");
2128 econv_description(sname, dname, ecflags, mesg);
2129 rb_str_cat2(mesg, ")");
2130 exc = rb_exc_new3(rb_eConverterNotFoundError, mesg);
2131 return exc;
2132}
2133
2134static VALUE
2135make_econv_exception(rb_econv_t *ec)
2136{
2137 VALUE mesg, exc;
2138 if (ec->last_error.result == econv_invalid_byte_sequence ||
2139 ec->last_error.result == econv_incomplete_input) {
2140 const char *err = (const char *)ec->last_error.error_bytes_start;
2141 size_t error_len = ec->last_error.error_bytes_len;
2142 VALUE bytes = rb_str_new(err, error_len);
2143 VALUE dumped = rb_str_dump(bytes);
2144 size_t readagain_len = ec->last_error.readagain_len;
2145 VALUE bytes2 = Qnil;
2146 VALUE dumped2;
2147 if (ec->last_error.result == econv_incomplete_input) {
2148 mesg = rb_sprintf("incomplete %s on %s",
2149 StringValueCStr(dumped),
2150 ec->last_error.source_encoding);
2151 }
2152 else if (readagain_len) {
2153 bytes2 = rb_str_new(err+error_len, readagain_len);
2154 dumped2 = rb_str_dump(bytes2);
2155 mesg = rb_sprintf("%s followed by %s on %s",
2156 StringValueCStr(dumped),
2157 StringValueCStr(dumped2),
2158 ec->last_error.source_encoding);
2159 }
2160 else {
2161 mesg = rb_sprintf("%s on %s",
2162 StringValueCStr(dumped),
2163 ec->last_error.source_encoding);
2164 }
2165
2166 exc = rb_exc_new3(rb_eInvalidByteSequenceError, mesg);
2167 rb_ivar_set(exc, id_error_bytes, bytes);
2168 rb_ivar_set(exc, id_readagain_bytes, bytes2);
2169 rb_ivar_set(exc, id_incomplete_input, RBOOL(ec->last_error.result == econv_incomplete_input));
2170 goto set_encs;
2171 }
2172 if (ec->last_error.result == econv_undefined_conversion) {
2173 VALUE bytes = rb_str_new((const char *)ec->last_error.error_bytes_start,
2174 ec->last_error.error_bytes_len);
2175 VALUE dumped = Qnil;
2176 int idx;
2177 if (strcmp(ec->last_error.source_encoding, "UTF-8") == 0) {
2178 rb_encoding *utf8 = rb_utf8_encoding();
2179 const char *start, *end;
2180 int n;
2181 start = (const char *)ec->last_error.error_bytes_start;
2182 end = start + ec->last_error.error_bytes_len;
2183 n = rb_enc_precise_mbclen(start, end, utf8);
2184 if (MBCLEN_CHARFOUND_P(n) &&
2185 (size_t)MBCLEN_CHARFOUND_LEN(n) == ec->last_error.error_bytes_len) {
2186 unsigned int cc = rb_enc_mbc_to_codepoint(start, end, utf8);
2187 dumped = rb_sprintf("U+%04X", cc);
2188 }
2189 }
2190 if (NIL_P(dumped))
2191 dumped = rb_str_dump(bytes);
2192 if (strcmp(ec->last_error.source_encoding,
2193 ec->source_encoding_name) == 0 &&
2194 strcmp(ec->last_error.destination_encoding,
2195 ec->destination_encoding_name) == 0) {
2196 mesg = rb_sprintf("%s from %s to %s",
2197 StringValueCStr(dumped),
2198 ec->last_error.source_encoding,
2199 ec->last_error.destination_encoding);
2200 }
2201 else {
2202 int i;
2203 mesg = rb_sprintf("%s to %s in conversion from %s",
2204 StringValueCStr(dumped),
2205 ec->last_error.destination_encoding,
2206 ec->source_encoding_name);
2207 for (i = 0; i < ec->num_trans; i++) {
2208 const rb_transcoder *tr = ec->elems[i].tc->transcoder;
2209 if (!DECORATOR_P(tr->src_encoding, tr->dst_encoding))
2210 rb_str_catf(mesg, " to %s",
2211 ec->elems[i].tc->transcoder->dst_encoding);
2212 }
2213 }
2214 exc = rb_exc_new3(rb_eUndefinedConversionError, mesg);
2215 idx = rb_enc_find_index(ec->last_error.source_encoding);
2216 if (0 <= idx)
2217 rb_enc_associate_index(bytes, idx);
2218 rb_ivar_set(exc, id_error_char, bytes);
2219 goto set_encs;
2220 }
2221 return Qnil;
2222
2223 set_encs:
2224 rb_ivar_set(exc, id_source_encoding_name, rb_str_new2(ec->last_error.source_encoding));
2225 rb_ivar_set(exc, id_destination_encoding_name, rb_str_new2(ec->last_error.destination_encoding));
2226 int idx = rb_enc_find_index(ec->last_error.source_encoding);
2227 if (0 <= idx)
2228 rb_ivar_set(exc, id_source_encoding, rb_enc_from_encoding(rb_enc_from_index(idx)));
2229 idx = rb_enc_find_index(ec->last_error.destination_encoding);
2230 if (0 <= idx)
2231 rb_ivar_set(exc, id_destination_encoding, rb_enc_from_encoding(rb_enc_from_index(idx)));
2232 return exc;
2233}
2234
2235static void
2236more_output_buffer(
2237 VALUE destination,
2238 unsigned char *(*resize_destination)(VALUE, size_t, size_t),
2239 int max_output,
2240 unsigned char **out_start_ptr,
2241 unsigned char **out_pos,
2242 unsigned char **out_stop_ptr)
2243{
2244 size_t len = (*out_pos - *out_start_ptr);
2245 size_t new_len = (len + max_output) * 2;
2246 *out_start_ptr = resize_destination(destination, len, new_len);
2247 *out_pos = *out_start_ptr + len;
2248 *out_stop_ptr = *out_start_ptr + new_len;
2249}
2250
2251static int
2252make_replacement(rb_econv_t *ec)
2253{
2254 rb_transcoding *tc;
2255 const rb_transcoder *tr;
2256 const unsigned char *replacement;
2257 const char *repl_enc;
2258 const char *ins_enc;
2259 size_t len;
2260
2261 if (ec->replacement_str)
2262 return 0;
2263
2265
2266 tc = ec->last_tc;
2267 if (*ins_enc) {
2268 tr = tc->transcoder;
2269 rb_enc_find(tr->dst_encoding);
2270 replacement = (const unsigned char *)get_replacement_character(ins_enc, &len, &repl_enc);
2271 }
2272 else {
2273 replacement = (unsigned char *)"?";
2274 len = 1;
2275 repl_enc = "";
2276 }
2277
2278 ec->replacement_str = replacement;
2279 ec->replacement_len = len;
2280 ec->replacement_bufsize = len;
2281 ec->replacement_enc = repl_enc;
2282 ec->replacement_allocated = 0;
2283 return 0;
2284}
2285
2286int
2288 const unsigned char *str, size_t len, const char *encname)
2289{
2290 unsigned char *str2;
2291 size_t len2, buf_size2;
2292 const char *encname2;
2293
2295
2296 if (!*encname2 || encoding_equal(encname, encname2)) {
2297 str2 = xmalloc(len);
2298 MEMCPY(str2, str, unsigned char, len); /* xxx: str may be invalid */
2299 buf_size2 = len2 = len;
2300 encname2 = encname;
2301 }
2302 else {
2303 str2 = allocate_converted_string(encname, encname2, str, len, NULL, 0, &len2, &buf_size2);
2304 if (!str2)
2305 return -1;
2306 }
2307
2308 if (ec->replacement_allocated) {
2309 SIZED_FREE_N((char *)ec->replacement_str, ec->replacement_bufsize);
2310 }
2311 ec->replacement_allocated = 1;
2312 ec->replacement_str = str2;
2313 ec->replacement_len = len2;
2314 ec->replacement_bufsize = buf_size2;
2315 ec->replacement_enc = encname2;
2316 return 0;
2317}
2318
2319static int
2320output_replacement_character(rb_econv_t *ec)
2321{
2322 int ret;
2323
2324 if (make_replacement(ec) == -1)
2325 return -1;
2326
2327 ret = rb_econv_insert_output(ec, ec->replacement_str, ec->replacement_len, ec->replacement_enc);
2328 if (ret == -1)
2329 return -1;
2330
2331 return 0;
2332}
2333
2334#if 1
2335#define hash_fallback rb_hash_aref
2336
2337static VALUE
2338proc_fallback(VALUE fallback, VALUE c)
2339{
2340 return rb_proc_call(fallback, rb_ary_new4(1, &c));
2341}
2342
2343static VALUE
2344method_fallback(VALUE fallback, VALUE c)
2345{
2346 return rb_method_call(1, &c, fallback);
2347}
2348
2349static VALUE
2350aref_fallback(VALUE fallback, VALUE c)
2351{
2352 return rb_funcallv_public(fallback, idAREF, 1, &c);
2353}
2354
2356 VALUE (*fallback_func)(VALUE, VALUE);
2357 VALUE fallback;
2358 VALUE rep;
2359};
2360
2361static VALUE
2362transcode_loop_fallback_try(VALUE a)
2363{
2365
2366 VALUE ret = args->fallback_func(args->fallback, args->rep);
2367
2368 if (!UNDEF_P(ret) && !NIL_P(ret)) {
2369 StringValue(ret);
2370 }
2371
2372 return ret;
2373}
2374
2375static void
2376transcode_loop(const unsigned char **in_pos, unsigned char **out_pos,
2377 const unsigned char *in_stop, unsigned char *out_stop,
2378 VALUE destination,
2379 unsigned char *(*resize_destination)(VALUE, size_t, size_t),
2380 const char *src_encoding,
2381 const char *dst_encoding,
2382 int ecflags,
2383 VALUE ecopts)
2384{
2385 rb_econv_t *ec;
2386 rb_transcoding *last_tc;
2388 unsigned char *out_start = *out_pos;
2389 int max_output;
2390 VALUE exc;
2391 VALUE fallback = Qnil;
2392 VALUE (*fallback_func)(VALUE, VALUE) = 0;
2393
2394 ec = rb_econv_open_opts(src_encoding, dst_encoding, ecflags, ecopts);
2395 if (!ec)
2396 rb_exc_raise(rb_econv_open_exc(src_encoding, dst_encoding, ecflags));
2397
2398 if (!NIL_P(ecopts) && RB_TYPE_P(ecopts, T_HASH)) {
2399 fallback = rb_hash_aref(ecopts, sym_fallback);
2400 if (RB_TYPE_P(fallback, T_HASH)) {
2401 fallback_func = hash_fallback;
2402 }
2403 else if (rb_obj_is_proc(fallback)) {
2404 fallback_func = proc_fallback;
2405 }
2406 else if (rb_obj_is_method(fallback)) {
2407 fallback_func = method_fallback;
2408 }
2409 else {
2410 fallback_func = aref_fallback;
2411 }
2412 }
2413 last_tc = ec->last_tc;
2414 max_output = last_tc ? last_tc->transcoder->max_output : 1;
2415
2416 resume:
2417 ret = rb_econv_convert(ec, in_pos, in_stop, out_pos, out_stop, 0);
2418
2419 if (!NIL_P(fallback) && ret == econv_undefined_conversion) {
2420 VALUE rep = rb_enc_str_new(
2421 (const char *)ec->last_error.error_bytes_start,
2422 ec->last_error.error_bytes_len,
2423 rb_enc_find(ec->last_error.source_encoding));
2424
2425
2426 struct transcode_loop_fallback_args args = {
2427 .fallback_func = fallback_func,
2428 .fallback = fallback,
2429 .rep = rep,
2430 };
2431
2432 int state;
2433 rep = rb_protect(transcode_loop_fallback_try, (VALUE)&args, &state);
2434 if (state) {
2435 rb_econv_close(ec);
2436 rb_jump_tag(state);
2437 }
2438
2439 if (!UNDEF_P(rep) && !NIL_P(rep)) {
2440 ret = rb_econv_insert_output(ec, (const unsigned char *)RSTRING_PTR(rep),
2441 RSTRING_LEN(rep), rb_enc_name(rb_enc_get(rep)));
2442 RB_GC_GUARD(rep); // insert_output may GC while reading rep's bytes
2443 if ((int)ret == -1) {
2444 rb_econv_close(ec);
2445 rb_raise(rb_eArgError, "too big fallback string");
2446 }
2447 goto resume;
2448 }
2449 }
2450
2451 if (ret == econv_invalid_byte_sequence ||
2452 ret == econv_incomplete_input ||
2454 exc = make_econv_exception(ec);
2455 rb_econv_close(ec);
2456 rb_exc_raise(exc);
2457 }
2458
2459 if (ret == econv_destination_buffer_full) {
2460 more_output_buffer(destination, resize_destination, max_output, &out_start, out_pos, &out_stop);
2461 goto resume;
2462 }
2463
2464 rb_econv_close(ec);
2465 return;
2466}
2467#else
2468/* sample transcode_loop implementation in byte-by-byte stream style */
2469static void
2470transcode_loop(const unsigned char **in_pos, unsigned char **out_pos,
2471 const unsigned char *in_stop, unsigned char *out_stop,
2472 VALUE destination,
2473 unsigned char *(*resize_destination)(VALUE, size_t, size_t),
2474 const char *src_encoding,
2475 const char *dst_encoding,
2476 int ecflags,
2477 VALUE ecopts)
2478{
2479 rb_econv_t *ec;
2480 rb_transcoding *last_tc;
2482 unsigned char *out_start = *out_pos;
2483 const unsigned char *ptr;
2484 int max_output;
2485 VALUE exc;
2486
2487 ec = rb_econv_open_opts(src_encoding, dst_encoding, ecflags, ecopts);
2488 if (!ec)
2489 rb_exc_raise(rb_econv_open_exc(src_encoding, dst_encoding, ecflags));
2490
2491 last_tc = ec->last_tc;
2492 max_output = last_tc ? last_tc->transcoder->max_output : 1;
2493
2495 ptr = *in_pos;
2496 while (ret != econv_finished) {
2497 unsigned char input_byte;
2498 const unsigned char *p = &input_byte;
2499
2500 if (ret == econv_source_buffer_empty) {
2501 if (ptr < in_stop) {
2502 input_byte = *ptr;
2503 ret = rb_econv_convert(ec, &p, p+1, out_pos, out_stop, ECONV_PARTIAL_INPUT);
2504 }
2505 else {
2506 ret = rb_econv_convert(ec, NULL, NULL, out_pos, out_stop, 0);
2507 }
2508 }
2509 else {
2510 ret = rb_econv_convert(ec, NULL, NULL, out_pos, out_stop, ECONV_PARTIAL_INPUT);
2511 }
2512 if (&input_byte != p)
2513 ptr += p - &input_byte;
2514 switch (ret) {
2518 exc = make_econv_exception(ec);
2519 rb_econv_close(ec);
2520 rb_exc_raise(exc);
2521 break;
2522
2524 more_output_buffer(destination, resize_destination, max_output, &out_start, out_pos, &out_stop);
2525 break;
2526
2528 break;
2529
2530 case econv_finished:
2531 break;
2532 }
2533 }
2534 rb_econv_close(ec);
2535 *in_pos = in_stop;
2536 return;
2537}
2538#endif
2539
2540
2541/*
2542 * String-specific code
2543 */
2544
2545static unsigned char *
2546str_transcoding_resize(VALUE destination, size_t len, size_t new_len)
2547{
2548 rb_str_resize(destination, new_len);
2549 return (unsigned char *)RSTRING_PTR(destination);
2550}
2551
2552static int
2553econv_opts(VALUE opt, int ecflags)
2554{
2555 VALUE v;
2556 int newlineflag = 0;
2557
2558 v = rb_hash_aref(opt, sym_invalid);
2559 if (NIL_P(v)) {
2560 }
2561 else if (v==sym_replace) {
2562 ecflags |= ECONV_INVALID_REPLACE;
2563 }
2564 else {
2565 rb_raise(rb_eArgError, "unknown value for invalid character option");
2566 }
2567
2568 v = rb_hash_aref(opt, sym_undef);
2569 if (NIL_P(v)) {
2570 }
2571 else if (v==sym_replace) {
2572 ecflags |= ECONV_UNDEF_REPLACE;
2573 }
2574 else {
2575 rb_raise(rb_eArgError, "unknown value for undefined character option");
2576 }
2577
2578 v = rb_hash_aref(opt, sym_replace);
2579 if (!NIL_P(v) && !(ecflags & ECONV_INVALID_REPLACE)) {
2580 ecflags |= ECONV_UNDEF_REPLACE;
2581 }
2582
2583 v = rb_hash_aref(opt, sym_xml);
2584 if (!NIL_P(v)) {
2585 if (v==sym_text) {
2587 }
2588 else if (v==sym_attr) {
2590 }
2591 else if (SYMBOL_P(v)) {
2592 rb_raise(rb_eArgError, "unexpected value for xml option: %"PRIsVALUE, rb_sym2str(v));
2593 }
2594 else {
2595 rb_raise(rb_eArgError, "unexpected value for xml option");
2596 }
2597 }
2598
2599#ifdef ENABLE_ECONV_NEWLINE_OPTION
2600 v = rb_hash_aref(opt, sym_newline);
2601 if (!NIL_P(v)) {
2602 newlineflag = 2;
2603 ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
2604 if (v == sym_universal) {
2606 }
2607 else if (v == sym_crlf) {
2609 }
2610 else if (v == sym_cr) {
2611 ecflags |= ECONV_CR_NEWLINE_DECORATOR;
2612 }
2613 else if (v == sym_lf) {
2614 ecflags |= ECONV_LF_NEWLINE_DECORATOR;
2615 }
2616 else if (SYMBOL_P(v)) {
2617 rb_raise(rb_eArgError, "unexpected value for newline option: %"PRIsVALUE,
2618 rb_sym2str(v));
2619 }
2620 else {
2621 rb_raise(rb_eArgError, "unexpected value for newline option");
2622 }
2623 }
2624#endif
2625 {
2626 int setflags = 0;
2627
2628 v = rb_hash_aref(opt, sym_universal_newline);
2629 if (RTEST(v))
2631 newlineflag |= !NIL_P(v);
2632
2633 v = rb_hash_aref(opt, sym_crlf_newline);
2634 if (RTEST(v))
2635 setflags |= ECONV_CRLF_NEWLINE_DECORATOR;
2636 newlineflag |= !NIL_P(v);
2637
2638 v = rb_hash_aref(opt, sym_cr_newline);
2639 if (RTEST(v))
2640 setflags |= ECONV_CR_NEWLINE_DECORATOR;
2641 newlineflag |= !NIL_P(v);
2642
2643 v = rb_hash_aref(opt, sym_lf_newline);
2644 if (RTEST(v))
2645 setflags |= ECONV_LF_NEWLINE_DECORATOR;
2646 newlineflag |= !NIL_P(v);
2647
2648 switch (newlineflag) {
2649 case 1:
2650 ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
2651 ecflags |= setflags;
2652 break;
2653
2654 case 3:
2655 rb_warning(":newline option precedes other newline options");
2656 break;
2657 }
2658 }
2659
2660 return ecflags;
2661}
2662
2663int
2664rb_econv_prepare_options(VALUE opthash, VALUE *opts, int ecflags)
2665{
2666 VALUE newhash = Qnil;
2667 VALUE v;
2668
2669 if (NIL_P(opthash)) {
2670 *opts = Qnil;
2671 return ecflags;
2672 }
2673 ecflags = econv_opts(opthash, ecflags);
2674
2675 v = rb_hash_aref(opthash, sym_replace);
2676 if (!NIL_P(v)) {
2677 StringValue(v);
2678 if (is_broken_string(v)) {
2679 VALUE dumped = rb_str_dump(v);
2680 rb_raise(rb_eArgError, "replacement string is broken: %s as %s",
2681 StringValueCStr(dumped),
2682 rb_enc_name(rb_enc_get(v)));
2683 }
2684 v = rb_str_new_frozen(v);
2685 newhash = rb_hash_new();
2686 rb_hash_aset(newhash, sym_replace, v);
2687 }
2688
2689 v = rb_hash_aref(opthash, sym_fallback);
2690 if (!NIL_P(v)) {
2691 VALUE h = rb_check_hash_type(v);
2692 if (NIL_P(h)
2693 ? (rb_obj_is_proc(v) || rb_obj_is_method(v) || rb_respond_to(v, idAREF))
2694 : (v = h, 1)) {
2695 if (NIL_P(newhash))
2696 newhash = rb_hash_new();
2697 rb_hash_aset(newhash, sym_fallback, v);
2698 }
2699 }
2700
2701 if (!NIL_P(newhash))
2702 rb_hash_freeze(newhash);
2703 *opts = newhash;
2704
2705 return ecflags;
2706}
2707
2708int
2710{
2711 return rb_econv_prepare_options(opthash, opts, 0);
2712}
2713
2714rb_econv_t *
2715rb_econv_open_opts(const char *source_encoding, const char *destination_encoding, int ecflags, VALUE opthash)
2716{
2717 rb_econv_t *ec;
2718 VALUE replacement;
2719
2720 if (NIL_P(opthash)) {
2721 replacement = Qnil;
2722 }
2723 else {
2724 if (!RB_TYPE_P(opthash, T_HASH) || !OBJ_FROZEN(opthash))
2725 rb_bug("rb_econv_open_opts called with invalid opthash");
2726 replacement = rb_hash_aref(opthash, sym_replace);
2727 }
2728
2729 ec = rb_econv_open(source_encoding, destination_encoding, ecflags);
2730 if (ec) {
2731 if (!NIL_P(replacement)) {
2732 int ret;
2733 rb_encoding *enc = rb_enc_get(replacement);
2734
2735 ret = rb_econv_set_replacement(ec,
2736 (const unsigned char *)RSTRING_PTR(replacement),
2737 RSTRING_LEN(replacement),
2738 rb_enc_name(enc));
2739 if (ret == -1) {
2740 rb_econv_close(ec);
2741 ec = NULL;
2742 }
2743 }
2744 }
2745 return ec; // can be NULL
2746}
2747
2748static int
2749enc_arg(VALUE *arg, const char **name_p, rb_encoding **enc_p)
2750{
2751 rb_encoding *enc;
2752 const char *n;
2753 int encidx;
2754 VALUE encval;
2755
2756 if (((encidx = rb_to_encoding_index(encval = *arg)) < 0) ||
2757 !(enc = rb_enc_from_index(encidx))) {
2758 enc = NULL;
2759 encidx = 0;
2760 n = StringValueCStr(*arg);
2761 }
2762 else {
2763 n = rb_enc_name(enc);
2764 }
2765
2766 *name_p = n;
2767 *enc_p = enc;
2768
2769 return encidx;
2770}
2771
2772static int
2773str_transcode_enc_args(VALUE str, VALUE *arg1, VALUE *arg2,
2774 const char **sname_p, rb_encoding **senc_p,
2775 const char **dname_p, rb_encoding **denc_p)
2776{
2777 rb_encoding *senc, *denc;
2778 const char *sname, *dname;
2779 int sencidx, dencidx;
2780
2781 dencidx = enc_arg(arg1, &dname, &denc);
2782
2783 if (NIL_P(*arg2)) {
2784 sencidx = rb_enc_get_index(str);
2785 senc = rb_enc_from_index(sencidx);
2786 sname = rb_enc_name(senc);
2787 }
2788 else {
2789 sencidx = enc_arg(arg2, &sname, &senc);
2790 }
2791
2792 *sname_p = sname;
2793 *senc_p = senc;
2794 *dname_p = dname;
2795 *denc_p = denc;
2796 return dencidx;
2797}
2798
2799static int
2800str_transcode0(int argc, VALUE *argv, VALUE *self, int ecflags, VALUE ecopts)
2801{
2802 VALUE dest;
2803 VALUE str = *self;
2804 VALUE arg1, arg2;
2805 long blen, slen;
2806 unsigned char *buf, *bp, *sp;
2807 const unsigned char *fromp;
2808 rb_encoding *senc, *denc;
2809 const char *sname, *dname;
2810 int dencidx;
2811 int explicitly_invalid_replace = TRUE;
2812
2813 rb_check_arity(argc, 0, 2);
2814
2815 if (argc == 0) {
2816 arg1 = rb_enc_default_internal();
2817 if (NIL_P(arg1)) {
2818 if (!ecflags) return -1;
2819 arg1 = rb_obj_encoding(str);
2820 }
2821 if (!(ecflags & ECONV_INVALID_MASK)) {
2822 explicitly_invalid_replace = FALSE;
2823 }
2825 }
2826 else {
2827 arg1 = argv[0];
2828 }
2829 arg2 = argc<=1 ? Qnil : argv[1];
2830 dencidx = str_transcode_enc_args(str, &arg1, &arg2, &sname, &senc, &dname, &denc);
2831
2832 if ((ecflags & (ECONV_NEWLINE_DECORATOR_MASK|
2836 if (senc && senc == denc) {
2837 if ((ecflags & ECONV_INVALID_MASK) && explicitly_invalid_replace) {
2838 VALUE rep = Qnil;
2839 if (!NIL_P(ecopts)) {
2840 rep = rb_hash_aref(ecopts, sym_replace);
2841 }
2842 dest = rb_enc_str_scrub(senc, str, rep);
2843 if (NIL_P(dest)) dest = str;
2844 *self = dest;
2845 return dencidx;
2846 }
2847 return NIL_P(arg2) ? -1 : dencidx;
2848 }
2849 if (senc && denc && rb_enc_asciicompat(senc) && rb_enc_asciicompat(denc)) {
2850 if (is_ascii_string(str)) {
2851 return dencidx;
2852 }
2853 }
2854 if (encoding_equal(sname, dname)) {
2855 return NIL_P(arg2) ? -1 : dencidx;
2856 }
2857 }
2858 else {
2859 if (senc && denc && !rb_enc_asciicompat(senc) && !rb_enc_asciicompat(denc)) {
2860 rb_encoding *utf8 = rb_utf8_encoding();
2861 str = rb_str_conv_enc(str, senc, utf8);
2862 senc = utf8;
2863 sname = "UTF-8";
2864 }
2865 if (encoding_equal(sname, dname)) {
2866 sname = "";
2867 dname = "";
2868 }
2869 }
2870
2871 fromp = sp = (unsigned char *)RSTRING_PTR(str);
2872 slen = RSTRING_LEN(str);
2873 blen = slen + 30; /* len + margin */
2874 dest = rb_str_tmp_new(blen);
2875 bp = (unsigned char *)RSTRING_PTR(dest);
2876
2877 transcode_loop(&fromp, &bp, (sp+slen), (bp+blen), dest, str_transcoding_resize, sname, dname, ecflags, ecopts);
2878 if (fromp != sp+slen) {
2879 rb_raise(rb_eArgError, "not fully converted, %"PRIdPTRDIFF" bytes left", sp+slen-fromp);
2880 }
2881 buf = (unsigned char *)RSTRING_PTR(dest);
2882 *bp = '\0';
2883 rb_str_set_len(dest, bp - buf);
2884
2885 /* set encoding */
2886 if (!denc) {
2887 dencidx = rb_define_dummy_encoding(dname);
2888 RB_GC_GUARD(arg1);
2889 RB_GC_GUARD(arg2);
2890 }
2891 *self = dest;
2892
2893 return dencidx;
2894}
2895
2896static int
2897str_transcode(int argc, VALUE *argv, VALUE *self)
2898{
2899 VALUE opt;
2900 int ecflags = 0;
2901 VALUE ecopts = Qnil;
2902
2903 argc = rb_scan_args(argc, argv, "02:", NULL, NULL, &opt);
2904 if (!NIL_P(opt)) {
2905 ecflags = rb_econv_prepare_opts(opt, &ecopts);
2906 }
2907 return str_transcode0(argc, argv, self, ecflags, ecopts);
2908}
2909
2910static inline VALUE
2911str_encode_associate(VALUE str, int encidx)
2912{
2913 int cr = 0;
2914
2915 rb_enc_associate_index(str, encidx);
2916
2917 /* transcoded string never be broken. */
2918 if (rb_enc_asciicompat(rb_enc_from_index(encidx))) {
2919 rb_str_coderange_scan_restartable(RSTRING_PTR(str), RSTRING_END(str), 0, &cr);
2920 }
2921 else {
2923 }
2924 ENC_CODERANGE_SET(str, cr);
2925 return str;
2926}
2927
2928/*
2929 * call-seq:
2930 * encode!(dst_encoding = Encoding.default_internal, **enc_opts) -> self
2931 * encode!(dst_encoding, src_encoding, **enc_opts) -> self
2932 *
2933 * Like #encode, but applies encoding changes to +self+; returns +self+.
2934 *
2935 * Related: see {Modifying}[rdoc-ref:String@Modifying].
2936 */
2937
2938static VALUE
2939str_encode_bang(int argc, VALUE *argv, VALUE str)
2940{
2941 VALUE newstr;
2942 int encidx;
2943
2944 rb_check_frozen(str);
2945
2946 newstr = str;
2947 encidx = str_transcode(argc, argv, &newstr);
2948
2949 if (encidx < 0) return str;
2950 if (newstr == str) {
2951 rb_enc_associate_index(str, encidx);
2952 return str;
2953 }
2954 rb_str_shared_replace(str, newstr);
2955 return str_encode_associate(str, encidx);
2956}
2957
2958static VALUE encoded_dup(VALUE newstr, VALUE str, int encidx);
2959
2960/*
2961 * call-seq:
2962 * encode(dst_encoding = Encoding.default_internal, **enc_opts) -> string
2963 * encode(dst_encoding, src_encoding, **enc_opts) -> string
2964 *
2965 * :include: doc/string/encode.rdoc
2966 *
2967 */
2968
2969static VALUE
2970str_encode(int argc, VALUE *argv, VALUE str)
2971{
2972 VALUE newstr = str;
2973 int encidx = str_transcode(argc, argv, &newstr);
2974 return encoded_dup(newstr, str, encidx);
2975}
2976
2977VALUE
2978rb_str_encode(VALUE str, VALUE to, int ecflags, VALUE ecopts)
2979{
2980 int argc = 1;
2981 VALUE *argv = &to;
2982 VALUE newstr = str;
2983 int encidx = str_transcode0(argc, argv, &newstr, ecflags, ecopts);
2984 return encoded_dup(newstr, str, encidx);
2985}
2986
2987static VALUE
2988encoded_dup(VALUE newstr, VALUE str, int encidx)
2989{
2990 if (encidx < 0) return rb_str_dup(str);
2991 if (newstr == str) {
2992 newstr = rb_str_dup(str);
2993 rb_enc_associate_index(newstr, encidx);
2994 return newstr;
2995 }
2996 else {
2997 RBASIC_SET_CLASS(newstr, rb_obj_class(str));
2998 }
2999 return str_encode_associate(newstr, encidx);
3000}
3001
3002/*
3003 * Document-class: Encoding::Converter
3004 *
3005 * Encoding conversion class.
3006 */
3007static void
3008econv_free(void *ptr)
3009{
3010 rb_econv_t *ec = ptr;
3011 rb_econv_close(ec);
3012}
3013
3014static size_t
3015econv_memsize(const void *ptr)
3016{
3017 return ptr ? rb_econv_memsize((rb_econv_t *)ptr) : 0;
3018}
3019
3020static const rb_data_type_t econv_data_type = {
3021 "econv",
3022 {0, econv_free, econv_memsize,},
3023 0, 0, RUBY_TYPED_THREAD_SAFE_FREE
3024};
3025
3026static VALUE
3027econv_s_allocate(VALUE klass)
3028{
3029 return TypedData_Wrap_Struct(klass, &econv_data_type, NULL);
3030}
3031
3032static rb_encoding *
3033make_dummy_encoding(const char *name)
3034{
3035 rb_encoding *enc;
3036 int idx;
3037 idx = rb_define_dummy_encoding(name);
3038 enc = rb_enc_from_index(idx);
3039 return enc;
3040}
3041
3042static rb_encoding *
3043make_encoding(const char *name)
3044{
3045 rb_encoding *enc;
3046 enc = rb_enc_find(name);
3047 if (!enc) {
3048 RB_VM_LOCKING() {
3049 if (rb_enc_registered(name)) {
3050 enc = NULL;
3051 }
3052 else {
3053 enc = make_dummy_encoding(name);
3054 }
3055 }
3056 }
3057 return enc;
3058}
3059
3060static VALUE
3061make_encobj(const char *name)
3062{
3063 return rb_enc_from_encoding(make_encoding(name));
3064}
3065
3066/*
3067 * call-seq:
3068 * Encoding::Converter.asciicompat_encoding(string) -> encoding or nil
3069 * Encoding::Converter.asciicompat_encoding(encoding) -> encoding or nil
3070 *
3071 * Returns the corresponding ASCII compatible encoding.
3072 *
3073 * Returns nil if the argument is an ASCII compatible encoding.
3074 *
3075 * "corresponding ASCII compatible encoding" is an ASCII compatible encoding which
3076 * can represents exactly the same characters as the given ASCII incompatible encoding.
3077 * So, no conversion undefined error occurs when converting between the two encodings.
3078 *
3079 * Encoding::Converter.asciicompat_encoding("ISO-2022-JP") #=> #<Encoding:stateless-ISO-2022-JP>
3080 * Encoding::Converter.asciicompat_encoding("UTF-16BE") #=> #<Encoding:UTF-8>
3081 * Encoding::Converter.asciicompat_encoding("UTF-8") #=> nil
3082 *
3083 */
3084static VALUE
3085econv_s_asciicompat_encoding(VALUE klass, VALUE arg)
3086{
3087 const char *arg_name, *result_name;
3088 rb_encoding *arg_enc, *result_enc;
3089 VALUE enc = Qnil;
3090
3091 enc_arg(&arg, &arg_name, &arg_enc);
3092 result_name = rb_econv_asciicompat_encoding(arg_name);
3093 if (result_name) {
3094 result_enc = make_encoding(result_name);
3095 enc = rb_enc_from_encoding(result_enc);
3096 }
3097 return enc;
3098}
3099
3100static void
3101econv_args(int argc, VALUE *argv,
3102 VALUE *snamev_p, VALUE *dnamev_p,
3103 const char **sname_p, const char **dname_p,
3104 rb_encoding **senc_p, rb_encoding **denc_p,
3105 int *ecflags_p,
3106 VALUE *ecopts_p)
3107{
3108 VALUE opt, flags_v, ecopts;
3109 int sidx, didx;
3110 const char *sname, *dname;
3111 rb_encoding *senc, *denc;
3112 int ecflags;
3113
3114 argc = rb_scan_args(argc, argv, "21:", snamev_p, dnamev_p, &flags_v, &opt);
3115
3116 if (!NIL_P(flags_v)) {
3117 if (!NIL_P(opt)) {
3118 rb_error_arity(argc + 1, 2, 3);
3119 }
3120 ecflags = NUM2INT(rb_to_int(flags_v));
3121 ecopts = Qnil;
3122 }
3123 else if (!NIL_P(opt)) {
3124 ecflags = rb_econv_prepare_opts(opt, &ecopts);
3125 }
3126 else {
3127 ecflags = 0;
3128 ecopts = Qnil;
3129 }
3130
3131 senc = NULL;
3132 sidx = rb_to_encoding_index(*snamev_p);
3133 if (0 <= sidx) {
3134 senc = rb_enc_from_index(sidx);
3135 }
3136 else {
3137 StringValue(*snamev_p);
3138 }
3139
3140 denc = NULL;
3141 didx = rb_to_encoding_index(*dnamev_p);
3142 if (0 <= didx) {
3143 denc = rb_enc_from_index(didx);
3144 }
3145 else {
3146 StringValue(*dnamev_p);
3147 }
3148
3149 sname = senc ? rb_enc_name(senc) : StringValueCStr(*snamev_p);
3150 dname = denc ? rb_enc_name(denc) : StringValueCStr(*dnamev_p);
3151
3152 *sname_p = sname;
3153 *dname_p = dname;
3154 *senc_p = senc;
3155 *denc_p = denc;
3156 *ecflags_p = ecflags;
3157 *ecopts_p = ecopts;
3158}
3159
3160static int
3161decorate_convpath(VALUE convpath, int ecflags)
3162{
3163 int num_decorators;
3164 const char *decorators[MAX_ECFLAGS_DECORATORS];
3165 int i;
3166 int n, len;
3167
3168 num_decorators = decorator_names(ecflags, decorators);
3169 if (num_decorators == -1)
3170 return -1;
3171
3172 len = n = RARRAY_LENINT(convpath);
3173 if (n != 0) {
3174 VALUE pair = RARRAY_AREF(convpath, n-1);
3175 if (RB_TYPE_P(pair, T_ARRAY)) {
3176 const char *sname = rb_enc_name(rb_to_encoding(RARRAY_AREF(pair, 0)));
3177 const char *dname = rb_enc_name(rb_to_encoding(RARRAY_AREF(pair, 1)));
3178 transcoder_entry_t *entry;
3179 const rb_transcoder *tr;
3180 entry = get_transcoder_entry(sname, dname);
3181 tr = load_transcoder_entry(entry);
3182 if (!tr)
3183 return -1;
3184 if (!DECORATOR_P(tr->src_encoding, tr->dst_encoding) &&
3185 tr->asciicompat_type == asciicompat_encoder) {
3186 n--;
3187 rb_ary_store(convpath, len + num_decorators - 1, pair);
3188 }
3189 }
3190 else {
3191 rb_ary_store(convpath, len + num_decorators - 1, pair);
3192 }
3193 }
3194
3195 for (i = 0; i < num_decorators; i++)
3196 rb_ary_store(convpath, n + i, rb_str_new_cstr(decorators[i]));
3197
3198 return 0;
3199}
3200
3201static void
3202search_convpath_i(const char *sname, const char *dname, int depth, void *arg)
3203{
3204 VALUE *ary_p = arg;
3205 VALUE v;
3206
3207 if (NIL_P(*ary_p)) {
3208 *ary_p = rb_ary_new();
3209 }
3210
3211 if (DECORATOR_P(sname, dname)) {
3212 v = rb_str_new_cstr(dname);
3213 }
3214 else {
3215 v = rb_assoc_new(make_encobj(sname), make_encobj(dname));
3216 }
3217 rb_ary_store(*ary_p, depth, v);
3218}
3219
3220/*
3221 * call-seq:
3222 * Encoding::Converter.search_convpath(source_encoding, destination_encoding) -> ary
3223 * Encoding::Converter.search_convpath(source_encoding, destination_encoding, opt) -> ary
3224 *
3225 * Returns a conversion path.
3226 *
3227 * p Encoding::Converter.search_convpath("ISO-8859-1", "EUC-JP")
3228 * #=> [[#<Encoding:ISO-8859-1>, #<Encoding:UTF-8>],
3229 * # [#<Encoding:UTF-8>, #<Encoding:EUC-JP>]]
3230 *
3231 * p Encoding::Converter.search_convpath("ISO-8859-1", "EUC-JP", universal_newline: true)
3232 * or
3233 * p Encoding::Converter.search_convpath("ISO-8859-1", "EUC-JP", newline: :universal)
3234 * #=> [[#<Encoding:ISO-8859-1>, #<Encoding:UTF-8>],
3235 * # [#<Encoding:UTF-8>, #<Encoding:EUC-JP>],
3236 * # "universal_newline"]
3237 *
3238 * p Encoding::Converter.search_convpath("ISO-8859-1", "UTF-32BE", universal_newline: true)
3239 * or
3240 * p Encoding::Converter.search_convpath("ISO-8859-1", "UTF-32BE", newline: :universal)
3241 * #=> [[#<Encoding:ISO-8859-1>, #<Encoding:UTF-8>],
3242 * # "universal_newline",
3243 * # [#<Encoding:UTF-8>, #<Encoding:UTF-32BE>]]
3244 */
3245static VALUE
3246econv_s_search_convpath(int argc, VALUE *argv, VALUE klass)
3247{
3248 VALUE snamev, dnamev;
3249 const char *sname, *dname;
3250 rb_encoding *senc, *denc;
3251 int ecflags;
3252 VALUE ecopts;
3253 VALUE convpath;
3254
3255 econv_args(argc, argv, &snamev, &dnamev, &sname, &dname, &senc, &denc, &ecflags, &ecopts);
3256
3257 convpath = Qnil;
3258 transcode_search_path(sname, dname, search_convpath_i, &convpath);
3259
3260 if (NIL_P(convpath)) {
3261 VALUE exc = rb_econv_open_exc(sname, dname, ecflags);
3262 RB_GC_GUARD(snamev);
3263 RB_GC_GUARD(dnamev);
3264 rb_exc_raise(exc);
3265 }
3266
3267 if (decorate_convpath(convpath, ecflags) == -1) {
3268 VALUE exc = rb_econv_open_exc(sname, dname, ecflags);
3269 RB_GC_GUARD(snamev);
3270 RB_GC_GUARD(dnamev);
3271 rb_exc_raise(exc);
3272 }
3273
3274 return convpath;
3275}
3276
3277/*
3278 * Check the existence of a conversion path.
3279 * Returns the number of converters in the conversion path.
3280 * result: >=0:success -1:failure
3281 */
3282int
3283rb_econv_has_convpath_p(const char* from_encoding, const char* to_encoding)
3284{
3285 VALUE convpath = Qnil;
3286 transcode_search_path(from_encoding, to_encoding, search_convpath_i,
3287 &convpath);
3288 return RTEST(convpath);
3289}
3290
3292 rb_econv_t *ec;
3293 int index;
3294 int ret;
3295};
3296
3297static void
3298rb_econv_init_by_convpath_i(const char *sname, const char *dname, int depth, void *arg)
3299{
3301 int ret;
3302
3303 if (a->ret == -1)
3304 return;
3305
3306 ret = rb_econv_add_converter(a->ec, sname, dname, a->index);
3307
3308 a->ret = ret;
3309 return;
3310}
3311
3312static rb_econv_t *
3313rb_econv_init_by_convpath(VALUE self, VALUE convpath,
3314 const char **sname_p, const char **dname_p,
3315 rb_encoding **senc_p, rb_encoding**denc_p)
3316{
3317 rb_econv_t *ec;
3318 long i;
3319 int ret, first=1;
3320 VALUE elt;
3321 rb_encoding *senc = 0, *denc = 0;
3322 const char *sname, *dname;
3323
3324 ec = rb_econv_alloc(RARRAY_LENINT(convpath));
3325 DATA_PTR(self) = ec;
3326
3327 for (i = 0; i < RARRAY_LEN(convpath); i++) {
3328 VALUE snamev, dnamev;
3329 VALUE pair;
3330 elt = rb_ary_entry(convpath, i);
3331 if (!NIL_P(pair = rb_check_array_type(elt))) {
3332 if (RARRAY_LEN(pair) != 2)
3333 rb_raise(rb_eArgError, "not a 2-element array in convpath");
3334 snamev = rb_ary_entry(pair, 0);
3335 enc_arg(&snamev, &sname, &senc);
3336 dnamev = rb_ary_entry(pair, 1);
3337 enc_arg(&dnamev, &dname, &denc);
3338 }
3339 else {
3340 sname = "";
3341 dname = StringValueCStr(elt);
3342 }
3343 if (DECORATOR_P(sname, dname)) {
3344 ret = rb_econv_add_converter(ec, sname, dname, ec->num_trans);
3345 if (ret == -1) {
3346 VALUE msg = rb_sprintf("decoration failed: %s", dname);
3347 RB_GC_GUARD(snamev);
3348 RB_GC_GUARD(dnamev);
3349 rb_exc_raise(rb_exc_new_str(rb_eArgError, msg));
3350 }
3351 }
3352 else {
3353 int j = ec->num_trans;
3354 struct rb_econv_init_by_convpath_t arg;
3355 arg.ec = ec;
3356 arg.index = ec->num_trans;
3357 arg.ret = 0;
3358 ret = transcode_search_path(sname, dname, rb_econv_init_by_convpath_i, &arg);
3359 if (ret == -1 || arg.ret == -1) {
3360 VALUE msg = rb_sprintf("adding conversion failed: %s to %s", sname, dname);
3361 RB_GC_GUARD(snamev);
3362 RB_GC_GUARD(dnamev);
3363 rb_exc_raise(rb_exc_new_str(rb_eArgError, msg));
3364 }
3365 if (first) {
3366 first = 0;
3367 *senc_p = senc;
3368 *sname_p = ec->elems[j].tc->transcoder->src_encoding;
3369 }
3370 *denc_p = denc;
3371 *dname_p = ec->elems[ec->num_trans-1].tc->transcoder->dst_encoding;
3372 }
3373 }
3374
3375 if (first) {
3376 *senc_p = NULL;
3377 *denc_p = NULL;
3378 *sname_p = "";
3379 *dname_p = "";
3380 }
3381
3382 ec->source_encoding_name = *sname_p;
3383 ec->destination_encoding_name = *dname_p;
3384
3385 return ec;
3386}
3387
3388/*
3389 * call-seq:
3390 * Encoding::Converter.new(source_encoding, destination_encoding)
3391 * Encoding::Converter.new(source_encoding, destination_encoding, opt)
3392 * Encoding::Converter.new(convpath)
3393 *
3394 * possible options elements:
3395 * hash form:
3396 * :invalid => nil # raise error on invalid byte sequence (default)
3397 * :invalid => :replace # replace invalid byte sequence
3398 * :undef => nil # raise error on undefined conversion (default)
3399 * :undef => :replace # replace undefined conversion
3400 * :replace => string # replacement string ("?" or "\uFFFD" if not specified)
3401 * :newline => :universal # decorator for converting CRLF and CR to LF
3402 * :newline => :lf # decorator for converting CRLF and CR to LF when writing
3403 * :newline => :crlf # decorator for converting LF to CRLF
3404 * :newline => :cr # decorator for converting LF to CR
3405 * :universal_newline => true # decorator for converting CRLF and CR to LF
3406 * :crlf_newline => true # decorator for converting LF to CRLF
3407 * :cr_newline => true # decorator for converting LF to CR
3408 * :lf_newline => true # decorator for converting CRLF and CR to LF when writing
3409 * :xml => :text # escape as XML CharData.
3410 * :xml => :attr # escape as XML AttValue
3411 * integer form:
3412 * Encoding::Converter::INVALID_REPLACE
3413 * Encoding::Converter::UNDEF_REPLACE
3414 * Encoding::Converter::UNDEF_HEX_CHARREF
3415 * Encoding::Converter::UNIVERSAL_NEWLINE_DECORATOR
3416 * Encoding::Converter::LF_NEWLINE_DECORATOR
3417 * Encoding::Converter::CRLF_NEWLINE_DECORATOR
3418 * Encoding::Converter::CR_NEWLINE_DECORATOR
3419 * Encoding::Converter::XML_TEXT_DECORATOR
3420 * Encoding::Converter::XML_ATTR_CONTENT_DECORATOR
3421 * Encoding::Converter::XML_ATTR_QUOTE_DECORATOR
3422 *
3423 * Encoding::Converter.new creates an instance of Encoding::Converter.
3424 *
3425 * Source_encoding and destination_encoding should be a string or
3426 * Encoding object.
3427 *
3428 * opt should be nil, a hash or an integer.
3429 *
3430 * convpath should be an array.
3431 * convpath may contain
3432 * - two-element arrays which contain encodings or encoding names, or
3433 * - strings representing decorator names.
3434 *
3435 * Encoding::Converter.new optionally takes an option.
3436 * The option should be a hash or an integer.
3437 * The option hash can contain :invalid => nil, etc.
3438 * The option integer should be logical-or of constants such as
3439 * Encoding::Converter::INVALID_REPLACE, etc.
3440 *
3441 * [:invalid => nil]
3442 * Raise error on invalid byte sequence. This is a default behavior.
3443 * [:invalid => :replace]
3444 * Replace invalid byte sequence by replacement string.
3445 * [:undef => nil]
3446 * Raise an error if a character in source_encoding is not defined in destination_encoding.
3447 * This is a default behavior.
3448 * [:undef => :replace]
3449 * Replace undefined character in destination_encoding with replacement string.
3450 * [:replace => string]
3451 * Specify the replacement string.
3452 * If not specified, "\uFFFD" is used for Unicode encodings and "?" for others.
3453 * [:universal_newline => true]
3454 * Convert CRLF and CR to LF.
3455 * [:crlf_newline => true]
3456 * Convert LF to CRLF.
3457 * [:cr_newline => true]
3458 * Convert LF to CR.
3459 * [:lf_newline => true]
3460 * Convert CRLF and CR to LF (when writing).
3461 * [:xml => :text]
3462 * Escape as XML CharData.
3463 * This form can be used as an HTML 4.0 #PCDATA.
3464 * - '&' -> '&amp;'
3465 * - '<' -> '&lt;'
3466 * - '>' -> '&gt;'
3467 * - undefined characters in destination_encoding -> hexadecimal CharRef such as &#xHH;
3468 * [:xml => :attr]
3469 * Escape as XML AttValue.
3470 * The converted result is quoted as "...".
3471 * This form can be used as an HTML 4.0 attribute value.
3472 * - '&' -> '&amp;'
3473 * - '<' -> '&lt;'
3474 * - '>' -> '&gt;'
3475 * - '"' -> '&quot;'
3476 * - undefined characters in destination_encoding -> hexadecimal CharRef such as &#xHH;
3477 *
3478 * Examples:
3479 * # UTF-16BE to UTF-8
3480 * ec = Encoding::Converter.new("UTF-16BE", "UTF-8")
3481 *
3482 * # Usually, decorators such as newline conversion are inserted last.
3483 * ec = Encoding::Converter.new("UTF-16BE", "UTF-8", :universal_newline => true)
3484 * p ec.convpath #=> [[#<Encoding:UTF-16BE>, #<Encoding:UTF-8>],
3485 * # "universal_newline"]
3486 *
3487 * # But, if the last encoding is ASCII incompatible,
3488 * # decorators are inserted before the last conversion.
3489 * ec = Encoding::Converter.new("UTF-8", "UTF-16BE", :crlf_newline => true)
3490 * p ec.convpath #=> ["crlf_newline",
3491 * # [#<Encoding:UTF-8>, #<Encoding:UTF-16BE>]]
3492 *
3493 * # Conversion path can be specified directly.
3494 * ec = Encoding::Converter.new(["universal_newline", ["EUC-JP", "UTF-8"], ["UTF-8", "UTF-16BE"]])
3495 * p ec.convpath #=> ["universal_newline",
3496 * # [#<Encoding:EUC-JP>, #<Encoding:UTF-8>],
3497 * # [#<Encoding:UTF-8>, #<Encoding:UTF-16BE>]]
3498 */
3499static VALUE
3500econv_init(int argc, VALUE *argv, VALUE self)
3501{
3502 VALUE ecopts;
3503 VALUE snamev, dnamev;
3504 const char *sname, *dname;
3505 rb_encoding *senc, *denc;
3506 rb_econv_t *ec;
3507 int ecflags;
3508 VALUE convpath;
3509
3510 if (rb_check_typeddata(self, &econv_data_type)) {
3511 rb_raise(rb_eTypeError, "already initialized");
3512 }
3513
3514 if (argc == 1 && !NIL_P(convpath = rb_check_array_type(argv[0]))) {
3515 ec = rb_econv_init_by_convpath(self, convpath, &sname, &dname, &senc, &denc);
3516 ecflags = 0;
3517 ecopts = Qnil;
3518 }
3519 else {
3520 econv_args(argc, argv, &snamev, &dnamev, &sname, &dname, &senc, &denc, &ecflags, &ecopts);
3521 ec = rb_econv_open_opts(sname, dname, ecflags, ecopts);
3522 }
3523
3524 if (!ec) {
3525 VALUE exc = rb_econv_open_exc(sname, dname, ecflags);
3526 RB_GC_GUARD(snamev);
3527 RB_GC_GUARD(dnamev);
3528 rb_exc_raise(exc);
3529 }
3530
3531 if (!DECORATOR_P(sname, dname)) {
3532 if (!senc)
3533 senc = make_dummy_encoding(sname);
3534 if (!denc)
3535 denc = make_dummy_encoding(dname);
3536 RB_GC_GUARD(snamev);
3537 RB_GC_GUARD(dnamev);
3538 }
3539
3540 ec->source_encoding = senc;
3541 ec->destination_encoding = denc;
3542
3543 DATA_PTR(self) = ec;
3544
3545 return self;
3546}
3547
3548/*
3549 * call-seq:
3550 * ec.inspect -> string
3551 *
3552 * Returns a printable version of <i>ec</i>
3553 *
3554 * ec = Encoding::Converter.new("iso-8859-1", "utf-8")
3555 * puts ec.inspect #=> #<Encoding::Converter: ISO-8859-1 to UTF-8>
3556 *
3557 */
3558static VALUE
3559econv_inspect(VALUE self)
3560{
3561 const char *cname = rb_obj_classname(self);
3562 rb_econv_t *ec;
3563
3564 TypedData_Get_Struct(self, rb_econv_t, &econv_data_type, ec);
3565 if (!ec)
3566 return rb_sprintf("#<%s: uninitialized>", cname);
3567 else {
3568 const char *sname = ec->source_encoding_name;
3569 const char *dname = ec->destination_encoding_name;
3570 VALUE str;
3571 str = rb_sprintf("#<%s: ", cname);
3572 econv_description(sname, dname, ec->flags, str);
3573 rb_str_cat2(str, ">");
3574 return str;
3575 }
3576}
3577
3578static rb_econv_t *
3579check_econv(VALUE self)
3580{
3581 rb_econv_t *ec;
3582
3583 TypedData_Get_Struct(self, rb_econv_t, &econv_data_type, ec);
3584 if (!ec) {
3585 rb_raise(rb_eTypeError, "uninitialized encoding converter");
3586 }
3587 return ec;
3588}
3589
3590static VALUE
3591econv_get_encoding(rb_encoding *encoding)
3592{
3593 if (!encoding)
3594 return Qnil;
3595 return rb_enc_from_encoding(encoding);
3596}
3597
3598/*
3599 * call-seq:
3600 * ec.source_encoding -> encoding
3601 *
3602 * Returns the source encoding as an Encoding object.
3603 */
3604static VALUE
3605econv_source_encoding(VALUE self)
3606{
3607 rb_econv_t *ec = check_econv(self);
3608 return econv_get_encoding(ec->source_encoding);
3609}
3610
3611/*
3612 * call-seq:
3613 * ec.destination_encoding -> encoding
3614 *
3615 * Returns the destination encoding as an Encoding object.
3616 */
3617static VALUE
3618econv_destination_encoding(VALUE self)
3619{
3620 rb_econv_t *ec = check_econv(self);
3621 return econv_get_encoding(ec->destination_encoding);
3622}
3623
3624/*
3625 * call-seq:
3626 * ec.convpath -> ary
3627 *
3628 * Returns the conversion path of ec.
3629 *
3630 * The result is an array of conversions.
3631 *
3632 * ec = Encoding::Converter.new("ISO-8859-1", "EUC-JP", crlf_newline: true)
3633 * p ec.convpath
3634 * #=> [[#<Encoding:ISO-8859-1>, #<Encoding:UTF-8>],
3635 * # [#<Encoding:UTF-8>, #<Encoding:EUC-JP>],
3636 * # "crlf_newline"]
3637 *
3638 * Each element of the array is a pair of encodings or a string.
3639 * A pair means an encoding conversion.
3640 * A string means a decorator.
3641 *
3642 * In the above example, [#<Encoding:ISO-8859-1>, #<Encoding:UTF-8>] means
3643 * a converter from ISO-8859-1 to UTF-8.
3644 * "crlf_newline" means newline converter from LF to CRLF.
3645 */
3646static VALUE
3647econv_convpath(VALUE self)
3648{
3649 rb_econv_t *ec = check_econv(self);
3650 VALUE result;
3651 int i;
3652
3653 result = rb_ary_new();
3654 for (i = 0; i < ec->num_trans; i++) {
3655 const rb_transcoder *tr = ec->elems[i].tc->transcoder;
3656 VALUE v;
3657 if (DECORATOR_P(tr->src_encoding, tr->dst_encoding))
3658 v = rb_str_new_cstr(tr->dst_encoding);
3659 else
3660 v = rb_assoc_new(make_encobj(tr->src_encoding), make_encobj(tr->dst_encoding));
3661 rb_ary_push(result, v);
3662 }
3663 return result;
3664}
3665
3666/*
3667 * call-seq:
3668 * ec == other -> true or false
3669 */
3670static VALUE
3671econv_equal(VALUE self, VALUE other)
3672{
3673 rb_econv_t *ec1 = check_econv(self);
3674 rb_econv_t *ec2;
3675 int i;
3676
3677 if (!rb_typeddata_is_kind_of(other, &econv_data_type)) {
3678 return Qnil;
3679 }
3680 ec2 = DATA_PTR(other);
3681 if (!ec2) return Qfalse;
3682 if (ec1->source_encoding_name != ec2->source_encoding_name &&
3683 strcmp(ec1->source_encoding_name, ec2->source_encoding_name))
3684 return Qfalse;
3685 if (ec1->destination_encoding_name != ec2->destination_encoding_name &&
3686 strcmp(ec1->destination_encoding_name, ec2->destination_encoding_name))
3687 return Qfalse;
3688 if (ec1->flags != ec2->flags) return Qfalse;
3689 if (ec1->replacement_enc != ec2->replacement_enc &&
3690 strcmp(ec1->replacement_enc, ec2->replacement_enc))
3691 return Qfalse;
3692 if (ec1->replacement_len != ec2->replacement_len) return Qfalse;
3693 if (ec1->replacement_str != ec2->replacement_str &&
3694 memcmp(ec1->replacement_str, ec2->replacement_str, ec2->replacement_len))
3695 return Qfalse;
3696
3697 if (ec1->num_trans != ec2->num_trans) return Qfalse;
3698 for (i = 0; i < ec1->num_trans; i++) {
3699 if (ec1->elems[i].tc->transcoder != ec2->elems[i].tc->transcoder)
3700 return Qfalse;
3701 }
3702 return Qtrue;
3703}
3704
3705static VALUE
3706econv_result_to_symbol(rb_econv_result_t res)
3707{
3708 switch (res) {
3709 case econv_invalid_byte_sequence: return sym_invalid_byte_sequence;
3710 case econv_incomplete_input: return sym_incomplete_input;
3711 case econv_undefined_conversion: return sym_undefined_conversion;
3712 case econv_destination_buffer_full: return sym_destination_buffer_full;
3713 case econv_source_buffer_empty: return sym_source_buffer_empty;
3714 case econv_finished: return sym_finished;
3715 case econv_after_output: return sym_after_output;
3716 default: return INT2NUM(res); /* should not be reached */
3717 }
3718}
3719
3720/*
3721 * call-seq:
3722 * ec.primitive_convert(source_buffer, destination_buffer) -> symbol
3723 * ec.primitive_convert(source_buffer, destination_buffer, destination_byteoffset) -> symbol
3724 * ec.primitive_convert(source_buffer, destination_buffer, destination_byteoffset, destination_bytesize) -> symbol
3725 * ec.primitive_convert(source_buffer, destination_buffer, destination_byteoffset, destination_bytesize, opt) -> symbol
3726 *
3727 * possible opt elements:
3728 * hash form:
3729 * :partial_input => true # source buffer may be part of larger source
3730 * :after_output => true # stop conversion after output before input
3731 * integer form:
3732 * Encoding::Converter::PARTIAL_INPUT
3733 * Encoding::Converter::AFTER_OUTPUT
3734 *
3735 * possible results:
3736 * :invalid_byte_sequence
3737 * :incomplete_input
3738 * :undefined_conversion
3739 * :after_output
3740 * :destination_buffer_full
3741 * :source_buffer_empty
3742 * :finished
3743 *
3744 * primitive_convert converts source_buffer into destination_buffer.
3745 *
3746 * source_buffer should be a string or nil.
3747 * nil means an empty string.
3748 *
3749 * destination_buffer should be a string.
3750 *
3751 * destination_byteoffset should be an integer or nil.
3752 * nil means the end of destination_buffer.
3753 * If it is omitted, nil is assumed.
3754 *
3755 * destination_bytesize should be an integer or nil.
3756 * nil means unlimited.
3757 * If it is omitted, nil is assumed.
3758 *
3759 * opt should be nil, a hash or an integer.
3760 * nil means no flags.
3761 * If it is omitted, nil is assumed.
3762 *
3763 * primitive_convert converts the content of source_buffer from beginning
3764 * and store the result into destination_buffer.
3765 *
3766 * destination_byteoffset and destination_bytesize specify the region which
3767 * the converted result is stored.
3768 * destination_byteoffset specifies the start position in destination_buffer in bytes.
3769 * If destination_byteoffset is nil,
3770 * destination_buffer.bytesize is used for appending the result.
3771 * destination_bytesize specifies maximum number of bytes.
3772 * If destination_bytesize is nil,
3773 * destination size is unlimited.
3774 * After conversion, destination_buffer is resized to
3775 * destination_byteoffset + actually produced number of bytes.
3776 * Also destination_buffer's encoding is set to destination_encoding.
3777 *
3778 * primitive_convert drops the converted part of source_buffer.
3779 * the dropped part is converted in destination_buffer or
3780 * buffered in Encoding::Converter object.
3781 *
3782 * primitive_convert stops conversion when one of following condition met.
3783 * - invalid byte sequence found in source buffer (:invalid_byte_sequence)
3784 * +primitive_errinfo+ and +last_error+ methods returns the detail of the error.
3785 * - unexpected end of source buffer (:incomplete_input)
3786 * this occur only when :partial_input is not specified.
3787 * +primitive_errinfo+ and +last_error+ methods returns the detail of the error.
3788 * - character not representable in output encoding (:undefined_conversion)
3789 * +primitive_errinfo+ and +last_error+ methods returns the detail of the error.
3790 * - after some output is generated, before input is done (:after_output)
3791 * this occur only when :after_output is specified.
3792 * - destination buffer is full (:destination_buffer_full)
3793 * this occur only when destination_bytesize is non-nil.
3794 * - source buffer is empty (:source_buffer_empty)
3795 * this occur only when :partial_input is specified.
3796 * - conversion is finished (:finished)
3797 *
3798 * example:
3799 * ec = Encoding::Converter.new("UTF-8", "UTF-16BE")
3800 * ret = ec.primitive_convert(src="pi", dst="", nil, 100)
3801 * p [ret, src, dst] #=> [:finished, "", "\x00p\x00i"]
3802 *
3803 * ec = Encoding::Converter.new("UTF-8", "UTF-16BE")
3804 * ret = ec.primitive_convert(src="pi", dst="", nil, 1)
3805 * p [ret, src, dst] #=> [:destination_buffer_full, "i", "\x00"]
3806 * ret = ec.primitive_convert(src, dst="", nil, 1)
3807 * p [ret, src, dst] #=> [:destination_buffer_full, "", "p"]
3808 * ret = ec.primitive_convert(src, dst="", nil, 1)
3809 * p [ret, src, dst] #=> [:destination_buffer_full, "", "\x00"]
3810 * ret = ec.primitive_convert(src, dst="", nil, 1)
3811 * p [ret, src, dst] #=> [:finished, "", "i"]
3812 *
3813 */
3814static VALUE
3815econv_primitive_convert(int argc, VALUE *argv, VALUE self)
3816{
3817 VALUE input, output, output_byteoffset_v, output_bytesize_v, opt, flags_v;
3818 rb_econv_t *ec = check_econv(self);
3820 const unsigned char *ip, *is;
3821 unsigned char *op, *os;
3822 long output_byteoffset, output_bytesize;
3823 unsigned long output_byteend;
3824 int flags;
3825
3826 argc = rb_scan_args(argc, argv, "23:", &input, &output, &output_byteoffset_v, &output_bytesize_v, &flags_v, &opt);
3827
3828 if (NIL_P(output_byteoffset_v))
3829 output_byteoffset = 0; /* dummy */
3830 else
3831 output_byteoffset = NUM2LONG(output_byteoffset_v);
3832
3833 if (NIL_P(output_bytesize_v))
3834 output_bytesize = 0; /* dummy */
3835 else
3836 output_bytesize = NUM2LONG(output_bytesize_v);
3837
3838 if (!NIL_P(flags_v)) {
3839 if (!NIL_P(opt)) {
3840 rb_error_arity(argc + 1, 2, 5);
3841 }
3842 flags = NUM2INT(rb_to_int(flags_v));
3843 }
3844 else if (!NIL_P(opt)) {
3845 VALUE v;
3846 flags = 0;
3847 v = rb_hash_aref(opt, sym_partial_input);
3848 if (RTEST(v))
3849 flags |= ECONV_PARTIAL_INPUT;
3850 v = rb_hash_aref(opt, sym_after_output);
3851 if (RTEST(v))
3852 flags |= ECONV_AFTER_OUTPUT;
3853 }
3854 else {
3855 flags = 0;
3856 }
3857
3858 StringValue(output);
3859 if (!NIL_P(input))
3860 StringValue(input);
3861 rb_str_modify(output);
3862
3863 if (NIL_P(output_bytesize_v)) {
3864 output_bytesize = rb_str_capacity(output);
3865
3866 if (!NIL_P(input) && output_bytesize < RSTRING_LEN(input))
3867 output_bytesize = RSTRING_LEN(input);
3868 }
3869
3870 retry:
3871
3872 if (NIL_P(output_byteoffset_v))
3873 output_byteoffset = RSTRING_LEN(output);
3874
3875 if (output_byteoffset < 0)
3876 rb_raise(rb_eArgError, "negative output_byteoffset");
3877
3878 if (RSTRING_LEN(output) < output_byteoffset)
3879 rb_raise(rb_eArgError, "output_byteoffset too big");
3880
3881 if (output_bytesize < 0)
3882 rb_raise(rb_eArgError, "negative output_bytesize");
3883
3884 output_byteend = (unsigned long)output_byteoffset +
3885 (unsigned long)output_bytesize;
3886
3887 if (output_byteend < (unsigned long)output_byteoffset ||
3888 LONG_MAX < output_byteend)
3889 rb_raise(rb_eArgError, "output_byteoffset+output_bytesize too big");
3890
3891 if (rb_str_capacity(output) < output_byteend)
3892 rb_str_resize(output, output_byteend);
3893
3894 if (NIL_P(input)) {
3895 ip = is = NULL;
3896 }
3897 else {
3898 ip = (const unsigned char *)RSTRING_PTR(input);
3899 is = ip + RSTRING_LEN(input);
3900 }
3901
3902 op = (unsigned char *)RSTRING_PTR(output) + output_byteoffset;
3903 os = op + output_bytesize;
3904
3905 res = rb_econv_convert(ec, &ip, is, &op, os, flags);
3906 rb_str_set_len(output, op-(unsigned char *)RSTRING_PTR(output));
3907 if (!NIL_P(input)) {
3908 rb_str_drop_bytes(input, ip - (unsigned char *)RSTRING_PTR(input));
3909 }
3910
3911 if (NIL_P(output_bytesize_v) && res == econv_destination_buffer_full) {
3912 if (LONG_MAX / 2 < output_bytesize)
3913 rb_raise(rb_eArgError, "too long conversion result");
3914 output_bytesize *= 2;
3915 output_byteoffset_v = Qnil;
3916 goto retry;
3917 }
3918
3919 if (ec->destination_encoding) {
3920 rb_enc_associate(output, ec->destination_encoding);
3921 }
3922
3923 return econv_result_to_symbol(res);
3924}
3925
3926/*
3927 * call-seq:
3928 * ec.convert(source_string) -> destination_string
3929 *
3930 * Convert source_string and return destination_string.
3931 *
3932 * source_string is assumed as a part of source.
3933 * i.e. :partial_input=>true is specified internally.
3934 * finish method should be used last.
3935 *
3936 * ec = Encoding::Converter.new("utf-8", "euc-jp")
3937 * puts ec.convert("\u3042").dump #=> "\xA4\xA2"
3938 * puts ec.finish.dump #=> ""
3939 *
3940 * ec = Encoding::Converter.new("euc-jp", "utf-8")
3941 * puts ec.convert("\xA4").dump #=> ""
3942 * puts ec.convert("\xA2").dump #=> "\xE3\x81\x82"
3943 * puts ec.finish.dump #=> ""
3944 *
3945 * ec = Encoding::Converter.new("utf-8", "iso-2022-jp")
3946 * puts ec.convert("\xE3").dump #=> "".force_encoding("ISO-2022-JP")
3947 * puts ec.convert("\x81").dump #=> "".force_encoding("ISO-2022-JP")
3948 * puts ec.convert("\x82").dump #=> "\e$B$\"".force_encoding("ISO-2022-JP")
3949 * puts ec.finish.dump #=> "\e(B".force_encoding("ISO-2022-JP")
3950 *
3951 * If a conversion error occur,
3952 * Encoding::UndefinedConversionError or
3953 * Encoding::InvalidByteSequenceError is raised.
3954 * Encoding::Converter#convert doesn't supply methods to recover or restart
3955 * from these exceptions.
3956 * When you want to handle these conversion errors,
3957 * use Encoding::Converter#primitive_convert.
3958 *
3959 */
3960static VALUE
3961econv_convert(VALUE self, VALUE source_string)
3962{
3963 VALUE ret, dst;
3964 VALUE av[5];
3965 int ac;
3966 rb_econv_t *ec = check_econv(self);
3967
3968 StringValue(source_string);
3969
3970 dst = rb_str_new(NULL, 0);
3971
3972 av[0] = rb_str_dup(source_string);
3973 av[1] = dst;
3974 av[2] = Qnil;
3975 av[3] = Qnil;
3977 ac = 5;
3978
3979 ret = econv_primitive_convert(ac, av, self);
3980
3981 if (ret == sym_invalid_byte_sequence ||
3982 ret == sym_undefined_conversion ||
3983 ret == sym_incomplete_input) {
3984 VALUE exc = make_econv_exception(ec);
3985 rb_exc_raise(exc);
3986 }
3987
3988 if (ret == sym_finished) {
3989 rb_raise(rb_eArgError, "converter already finished");
3990 }
3991
3992 if (ret != sym_source_buffer_empty) {
3993 rb_bug("unexpected result of econv_primitive_convert");
3994 }
3995
3996 return dst;
3997}
3998
3999/*
4000 * call-seq:
4001 * ec.finish -> string
4002 *
4003 * Finishes the converter.
4004 * It returns the last part of the converted string.
4005 *
4006 * ec = Encoding::Converter.new("utf-8", "iso-2022-jp")
4007 * p ec.convert("\u3042") #=> "\e$B$\""
4008 * p ec.finish #=> "\e(B"
4009 */
4010static VALUE
4011econv_finish(VALUE self)
4012{
4013 VALUE ret, dst;
4014 VALUE av[5];
4015 int ac;
4016 rb_econv_t *ec = check_econv(self);
4017
4018 dst = rb_str_new(NULL, 0);
4019
4020 av[0] = Qnil;
4021 av[1] = dst;
4022 av[2] = Qnil;
4023 av[3] = Qnil;
4024 av[4] = INT2FIX(0);
4025 ac = 5;
4026
4027 ret = econv_primitive_convert(ac, av, self);
4028
4029 if (ret == sym_invalid_byte_sequence ||
4030 ret == sym_undefined_conversion ||
4031 ret == sym_incomplete_input) {
4032 VALUE exc = make_econv_exception(ec);
4033 rb_exc_raise(exc);
4034 }
4035
4036 if (ret != sym_finished) {
4037 rb_bug("unexpected result of econv_primitive_convert");
4038 }
4039
4040 return dst;
4041}
4042
4043/*
4044 * call-seq:
4045 * ec.primitive_errinfo -> array
4046 *
4047 * primitive_errinfo returns important information regarding the last error
4048 * as a 5-element array:
4049 *
4050 * [result, enc1, enc2, error_bytes, readagain_bytes]
4051 *
4052 * result is the last result of primitive_convert.
4053 *
4054 * Other elements are only meaningful when result is
4055 * :invalid_byte_sequence, :incomplete_input or :undefined_conversion.
4056 *
4057 * enc1 and enc2 indicate a conversion step as a pair of strings.
4058 * For example, a converter from EUC-JP to ISO-8859-1 converts
4059 * a string as follows: EUC-JP -> UTF-8 -> ISO-8859-1.
4060 * So [enc1, enc2] is either ["EUC-JP", "UTF-8"] or ["UTF-8", "ISO-8859-1"].
4061 *
4062 * error_bytes and readagain_bytes indicate the byte sequences which caused the error.
4063 * error_bytes is discarded portion.
4064 * readagain_bytes is buffered portion which is read again on next conversion.
4065 *
4066 * Example:
4067 *
4068 * # \xff is invalid as EUC-JP.
4069 * ec = Encoding::Converter.new("EUC-JP", "Shift_JIS")
4070 * ec.primitive_convert(src="\xff", dst="", nil, 10)
4071 * p ec.primitive_errinfo
4072 * #=> [:invalid_byte_sequence, "EUC-JP", "Shift_JIS", "\xFF", ""]
4073 *
4074 * # HIRAGANA LETTER A (\xa4\xa2 in EUC-JP) is not representable in ISO-8859-1.
4075 * # Since this error is occur in UTF-8 to ISO-8859-1 conversion,
4076 * # error_bytes is HIRAGANA LETTER A in UTF-8 (\xE3\x81\x82).
4077 * ec = Encoding::Converter.new("EUC-JP", "ISO-8859-1")
4078 * ec.primitive_convert(src="\xa4\xa2", dst="", nil, 10)
4079 * p ec.primitive_errinfo
4080 * #=> [:undefined_conversion, "UTF-8", "ISO-8859-1", "\xE3\x81\x82", ""]
4081 *
4082 * # partial character is invalid
4083 * ec = Encoding::Converter.new("EUC-JP", "ISO-8859-1")
4084 * ec.primitive_convert(src="\xa4", dst="", nil, 10)
4085 * p ec.primitive_errinfo
4086 * #=> [:incomplete_input, "EUC-JP", "UTF-8", "\xA4", ""]
4087 *
4088 * # Encoding::Converter::PARTIAL_INPUT prevents invalid errors by
4089 * # partial characters.
4090 * ec = Encoding::Converter.new("EUC-JP", "ISO-8859-1")
4091 * ec.primitive_convert(src="\xa4", dst="", nil, 10, Encoding::Converter::PARTIAL_INPUT)
4092 * p ec.primitive_errinfo
4093 * #=> [:source_buffer_empty, nil, nil, nil, nil]
4094 *
4095 * # \xd8\x00\x00@ is invalid as UTF-16BE because
4096 * # no low surrogate after high surrogate (\xd8\x00).
4097 * # It is detected by 3rd byte (\00) which is part of next character.
4098 * # So the high surrogate (\xd8\x00) is discarded and
4099 * # the 3rd byte is read again later.
4100 * # Since the byte is buffered in ec, it is dropped from src.
4101 * ec = Encoding::Converter.new("UTF-16BE", "UTF-8")
4102 * ec.primitive_convert(src="\xd8\x00\x00@", dst="", nil, 10)
4103 * p ec.primitive_errinfo
4104 * #=> [:invalid_byte_sequence, "UTF-16BE", "UTF-8", "\xD8\x00", "\x00"]
4105 * p src
4106 * #=> "@"
4107 *
4108 * # Similar to UTF-16BE, \x00\xd8@\x00 is invalid as UTF-16LE.
4109 * # The problem is detected by 4th byte.
4110 * ec = Encoding::Converter.new("UTF-16LE", "UTF-8")
4111 * ec.primitive_convert(src="\x00\xd8@\x00", dst="", nil, 10)
4112 * p ec.primitive_errinfo
4113 * #=> [:invalid_byte_sequence, "UTF-16LE", "UTF-8", "\x00\xD8", "@\x00"]
4114 * p src
4115 * #=> ""
4116 *
4117 */
4118static VALUE
4119econv_primitive_errinfo(VALUE self)
4120{
4121 rb_econv_t *ec = check_econv(self);
4122
4123 VALUE ary;
4124
4125 ary = rb_ary_new2(5);
4126
4127 rb_ary_store(ary, 0, econv_result_to_symbol(ec->last_error.result));
4128 rb_ary_store(ary, 4, Qnil);
4129
4130 if (ec->last_error.source_encoding)
4131 rb_ary_store(ary, 1, rb_str_new2(ec->last_error.source_encoding));
4132
4133 if (ec->last_error.destination_encoding)
4134 rb_ary_store(ary, 2, rb_str_new2(ec->last_error.destination_encoding));
4135
4136 if (ec->last_error.error_bytes_start) {
4137 rb_ary_store(ary, 3, rb_str_new((const char *)ec->last_error.error_bytes_start, ec->last_error.error_bytes_len));
4138 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));
4139 }
4140
4141 return ary;
4142}
4143
4144/*
4145 * call-seq:
4146 * ec.insert_output(string) -> nil
4147 *
4148 * Inserts string into the encoding converter.
4149 * The string will be converted to the destination encoding and
4150 * output on later conversions.
4151 *
4152 * If the destination encoding is stateful,
4153 * string is converted according to the state and the state is updated.
4154 *
4155 * This method should be used only when a conversion error occurs.
4156 *
4157 * ec = Encoding::Converter.new("utf-8", "iso-8859-1")
4158 * src = "HIRAGANA LETTER A is \u{3042}."
4159 * dst = ""
4160 * p ec.primitive_convert(src, dst) #=> :undefined_conversion
4161 * puts "[#{dst.dump}, #{src.dump}]" #=> ["HIRAGANA LETTER A is ", "."]
4162 * ec.insert_output("<err>")
4163 * p ec.primitive_convert(src, dst) #=> :finished
4164 * puts "[#{dst.dump}, #{src.dump}]" #=> ["HIRAGANA LETTER A is <err>.", ""]
4165 *
4166 * ec = Encoding::Converter.new("utf-8", "iso-2022-jp")
4167 * src = "\u{306F 3041 3068 2661 3002}" # U+2661 is not representable in iso-2022-jp
4168 * dst = ""
4169 * p ec.primitive_convert(src, dst) #=> :undefined_conversion
4170 * puts "[#{dst.dump}, #{src.dump}]" #=> ["\e$B$O$!$H".force_encoding("ISO-2022-JP"), "\xE3\x80\x82"]
4171 * ec.insert_output "?" # state change required to output "?".
4172 * p ec.primitive_convert(src, dst) #=> :finished
4173 * puts "[#{dst.dump}, #{src.dump}]" #=> ["\e$B$O$!$H\e(B?\e$B!#\e(B".force_encoding("ISO-2022-JP"), ""]
4174 *
4175 */
4176static VALUE
4177econv_insert_output(VALUE self, VALUE string)
4178{
4179 const char *insert_enc;
4180
4181 int ret;
4182
4183 rb_econv_t *ec = check_econv(self);
4184
4185 StringValue(string);
4186 insert_enc = rb_econv_encoding_to_insert_output(ec);
4187 string = rb_str_encode(string, rb_enc_from_encoding(rb_enc_find(insert_enc)), 0, Qnil);
4188
4189 ret = rb_econv_insert_output(ec, (const unsigned char *)RSTRING_PTR(string), RSTRING_LEN(string), insert_enc);
4190 if (ret == -1) {
4191 rb_raise(rb_eArgError, "too big string");
4192 }
4193
4194 return Qnil;
4195}
4196
4197/*
4198 * call-seq:
4199 * ec.putback -> string
4200 * ec.putback(max_numbytes) -> string
4201 *
4202 * Put back the bytes which will be converted.
4203 *
4204 * The bytes are caused by invalid_byte_sequence error.
4205 * When invalid_byte_sequence error, some bytes are discarded and
4206 * some bytes are buffered to be converted later.
4207 * The latter bytes can be put back.
4208 * It can be observed by
4209 * Encoding::InvalidByteSequenceError#readagain_bytes and
4210 * Encoding::Converter#primitive_errinfo.
4211 *
4212 * ec = Encoding::Converter.new("utf-16le", "iso-8859-1")
4213 * src = "\x00\xd8\x61\x00"
4214 * dst = ""
4215 * p ec.primitive_convert(src, dst) #=> :invalid_byte_sequence
4216 * p ec.primitive_errinfo #=> [:invalid_byte_sequence, "UTF-16LE", "UTF-8", "\x00\xD8", "a\x00"]
4217 * p ec.putback #=> "a\x00"
4218 * p ec.putback #=> "" # no more bytes to put back
4219 *
4220 */
4221static VALUE
4222econv_putback(int argc, VALUE *argv, VALUE self)
4223{
4224 rb_econv_t *ec = check_econv(self);
4225 int n;
4226 int putbackable;
4227 VALUE str, max;
4228
4229 if (!rb_check_arity(argc, 0, 1) || NIL_P(max = argv[0])) {
4230 n = rb_econv_putbackable(ec);
4231 }
4232 else {
4233 n = NUM2INT(max);
4234 putbackable = rb_econv_putbackable(ec);
4235 if (putbackable < n)
4236 n = putbackable;
4237 }
4238
4239 str = rb_str_new(NULL, n);
4240 rb_econv_putback(ec, (unsigned char *)RSTRING_PTR(str), n);
4241
4242 if (ec->source_encoding) {
4243 rb_enc_associate(str, ec->source_encoding);
4244 }
4245
4246 return str;
4247}
4248
4249/*
4250 * call-seq:
4251 * ec.last_error -> exception or nil
4252 *
4253 * Returns an exception object for the last conversion.
4254 * Returns nil if the last conversion did not produce an error.
4255 *
4256 * "error" means that
4257 * Encoding::InvalidByteSequenceError and Encoding::UndefinedConversionError for
4258 * Encoding::Converter#convert and
4259 * :invalid_byte_sequence, :incomplete_input and :undefined_conversion for
4260 * Encoding::Converter#primitive_convert.
4261 *
4262 * ec = Encoding::Converter.new("utf-8", "iso-8859-1")
4263 * p ec.primitive_convert(src="\xf1abcd", dst="") #=> :invalid_byte_sequence
4264 * p ec.last_error #=> #<Encoding::InvalidByteSequenceError: "\xF1" followed by "a" on UTF-8>
4265 * p ec.primitive_convert(src, dst, nil, 1) #=> :destination_buffer_full
4266 * p ec.last_error #=> nil
4267 *
4268 */
4269static VALUE
4270econv_last_error(VALUE self)
4271{
4272 rb_econv_t *ec = check_econv(self);
4273 VALUE exc;
4274
4275 exc = make_econv_exception(ec);
4276 if (NIL_P(exc))
4277 return Qnil;
4278 return exc;
4279}
4280
4281/*
4282 * call-seq:
4283 * ec.replacement -> string
4284 *
4285 * Returns the replacement string.
4286 *
4287 * ec = Encoding::Converter.new("euc-jp", "us-ascii")
4288 * p ec.replacement #=> "?"
4289 *
4290 * ec = Encoding::Converter.new("euc-jp", "utf-8")
4291 * p ec.replacement #=> "\uFFFD"
4292 */
4293static VALUE
4294econv_get_replacement(VALUE self)
4295{
4296 rb_econv_t *ec = check_econv(self);
4297 int ret;
4298 rb_encoding *enc;
4299
4300 ret = make_replacement(ec);
4301 if (ret == -1) {
4302 rb_raise(rb_eUndefinedConversionError, "replacement character setup failed");
4303 }
4304
4305 enc = rb_enc_find(ec->replacement_enc);
4306 return rb_enc_str_new((const char *)ec->replacement_str, (long)ec->replacement_len, enc);
4307}
4308
4309/*
4310 * call-seq:
4311 * ec.replacement = string
4312 *
4313 * Sets the replacement string.
4314 *
4315 * ec = Encoding::Converter.new("utf-8", "us-ascii", :undef => :replace)
4316 * ec.replacement = "<undef>"
4317 * p ec.convert("a \u3042 b") #=> "a <undef> b"
4318 */
4319static VALUE
4320econv_set_replacement(VALUE self, VALUE arg)
4321{
4322 rb_econv_t *ec = check_econv(self);
4323 VALUE string = arg;
4324 int ret;
4325 rb_encoding *enc;
4326
4327 StringValue(string);
4328 enc = rb_enc_get(string);
4329
4330 ret = rb_econv_set_replacement(ec,
4331 (const unsigned char *)RSTRING_PTR(string),
4332 RSTRING_LEN(string),
4333 rb_enc_name(enc));
4334
4335 if (ret == -1) {
4336 /* xxx: rb_eInvalidByteSequenceError? */
4337 rb_raise(rb_eUndefinedConversionError, "replacement character setup failed");
4338 }
4339
4340 return arg;
4341}
4342
4343VALUE
4345{
4346 return make_econv_exception(ec);
4347}
4348
4349void
4351{
4352 VALUE exc;
4353
4354 exc = make_econv_exception(ec);
4355 if (NIL_P(exc))
4356 return;
4357 rb_exc_raise(exc);
4358}
4359
4360/*
4361 * call-seq:
4362 * ecerr.source_encoding_name -> string
4363 *
4364 * Returns the source encoding name as a string.
4365 */
4366static VALUE
4367ecerr_source_encoding_name(VALUE self)
4368{
4369 return rb_attr_get(self, id_source_encoding_name);
4370}
4371
4372/*
4373 * call-seq:
4374 * ecerr.source_encoding -> encoding
4375 *
4376 * Returns the source encoding as an encoding object.
4377 *
4378 * Note that the result may not be equal to the source encoding of
4379 * the encoding converter if the conversion has multiple steps.
4380 *
4381 * ec = Encoding::Converter.new("ISO-8859-1", "EUC-JP") # ISO-8859-1 -> UTF-8 -> EUC-JP
4382 * begin
4383 * ec.convert("\xa0") # NO-BREAK SPACE, which is available in UTF-8 but not in EUC-JP.
4384 * rescue Encoding::UndefinedConversionError
4385 * p $!.source_encoding #=> #<Encoding:UTF-8>
4386 * p $!.destination_encoding #=> #<Encoding:EUC-JP>
4387 * p $!.source_encoding_name #=> "UTF-8"
4388 * p $!.destination_encoding_name #=> "EUC-JP"
4389 * end
4390 *
4391 */
4392static VALUE
4393ecerr_source_encoding(VALUE self)
4394{
4395 return rb_attr_get(self, id_source_encoding);
4396}
4397
4398/*
4399 * call-seq:
4400 * ecerr.destination_encoding_name -> string
4401 *
4402 * Returns the destination encoding name as a string.
4403 */
4404static VALUE
4405ecerr_destination_encoding_name(VALUE self)
4406{
4407 return rb_attr_get(self, id_destination_encoding_name);
4408}
4409
4410/*
4411 * call-seq:
4412 * ecerr.destination_encoding -> string
4413 *
4414 * Returns the destination encoding as an encoding object.
4415 */
4416static VALUE
4417ecerr_destination_encoding(VALUE self)
4418{
4419 return rb_attr_get(self, id_destination_encoding);
4420}
4421
4422/*
4423 * call-seq:
4424 * ecerr.error_char -> string
4425 *
4426 * Returns the one-character string which cause Encoding::UndefinedConversionError.
4427 *
4428 * ec = Encoding::Converter.new("ISO-8859-1", "EUC-JP")
4429 * begin
4430 * ec.convert("\xa0")
4431 * rescue Encoding::UndefinedConversionError
4432 * puts $!.error_char.dump #=> "\xC2\xA0"
4433 * p $!.error_char.encoding #=> #<Encoding:UTF-8>
4434 * end
4435 *
4436 */
4437static VALUE
4438ecerr_error_char(VALUE self)
4439{
4440 return rb_attr_get(self, id_error_char);
4441}
4442
4443/*
4444 * call-seq:
4445 * ecerr.error_bytes -> string
4446 *
4447 * Returns the discarded bytes when Encoding::InvalidByteSequenceError occurs.
4448 *
4449 * ec = Encoding::Converter.new("EUC-JP", "ISO-8859-1")
4450 * begin
4451 * ec.convert("abc\xA1\xFFdef")
4452 * rescue Encoding::InvalidByteSequenceError
4453 * p $! #=> #<Encoding::InvalidByteSequenceError: "\xA1" followed by "\xFF" on EUC-JP>
4454 * puts $!.error_bytes.dump #=> "\xA1"
4455 * puts $!.readagain_bytes.dump #=> "\xFF"
4456 * end
4457 */
4458static VALUE
4459ecerr_error_bytes(VALUE self)
4460{
4461 return rb_attr_get(self, id_error_bytes);
4462}
4463
4464/*
4465 * call-seq:
4466 * ecerr.readagain_bytes -> string
4467 *
4468 * Returns the bytes to be read again when Encoding::InvalidByteSequenceError occurs.
4469 */
4470static VALUE
4471ecerr_readagain_bytes(VALUE self)
4472{
4473 return rb_attr_get(self, id_readagain_bytes);
4474}
4475
4476/*
4477 * call-seq:
4478 * ecerr.incomplete_input? -> true or false
4479 *
4480 * Returns true if the invalid byte sequence error is caused by
4481 * premature end of string.
4482 *
4483 * ec = Encoding::Converter.new("EUC-JP", "ISO-8859-1")
4484 *
4485 * begin
4486 * ec.convert("abc\xA1z")
4487 * rescue Encoding::InvalidByteSequenceError
4488 * p $! #=> #<Encoding::InvalidByteSequenceError: "\xA1" followed by "z" on EUC-JP>
4489 * p $!.incomplete_input? #=> false
4490 * end
4491 *
4492 * begin
4493 * ec.convert("abc\xA1")
4494 * ec.finish
4495 * rescue Encoding::InvalidByteSequenceError
4496 * p $! #=> #<Encoding::InvalidByteSequenceError: incomplete "\xA1" on EUC-JP>
4497 * p $!.incomplete_input? #=> true
4498 * end
4499 */
4500static VALUE
4501ecerr_incomplete_input(VALUE self)
4502{
4503 return rb_attr_get(self, id_incomplete_input);
4504}
4505
4506/*
4507 * Document-class: Encoding::UndefinedConversionError
4508 *
4509 * Raised by Encoding and String methods when a transcoding operation
4510 * fails.
4511 */
4512
4513/*
4514 * Document-class: Encoding::InvalidByteSequenceError
4515 *
4516 * Raised by Encoding and String methods when the string being
4517 * transcoded contains a byte invalid for the either the source or
4518 * target encoding.
4519 */
4520
4521/*
4522 * Document-class: Encoding::ConverterNotFoundError
4523 *
4524 * Raised by transcoding methods when a named encoding does not
4525 * correspond with a known converter.
4526 */
4527
4528void
4529Init_transcode(void)
4530{
4531 transcoder_table = st_init_strcasetable();
4532
4533 id_destination_encoding = rb_intern_const("destination_encoding");
4534 id_destination_encoding_name = rb_intern_const("destination_encoding_name");
4535 id_error_bytes = rb_intern_const("error_bytes");
4536 id_error_char = rb_intern_const("error_char");
4537 id_incomplete_input = rb_intern_const("incomplete_input");
4538 id_readagain_bytes = rb_intern_const("readagain_bytes");
4539 id_source_encoding = rb_intern_const("source_encoding");
4540 id_source_encoding_name = rb_intern_const("source_encoding_name");
4541
4542 sym_invalid = ID2SYM(rb_intern_const("invalid"));
4543 sym_undef = ID2SYM(rb_intern_const("undef"));
4544 sym_replace = ID2SYM(rb_intern_const("replace"));
4545 sym_fallback = ID2SYM(rb_intern_const("fallback"));
4546 sym_xml = ID2SYM(rb_intern_const("xml"));
4547 sym_text = ID2SYM(rb_intern_const("text"));
4548 sym_attr = ID2SYM(rb_intern_const("attr"));
4549
4550 sym_invalid_byte_sequence = ID2SYM(rb_intern_const("invalid_byte_sequence"));
4551 sym_undefined_conversion = ID2SYM(rb_intern_const("undefined_conversion"));
4552 sym_destination_buffer_full = ID2SYM(rb_intern_const("destination_buffer_full"));
4553 sym_source_buffer_empty = ID2SYM(rb_intern_const("source_buffer_empty"));
4554 sym_finished = ID2SYM(rb_intern_const("finished"));
4555 sym_after_output = ID2SYM(rb_intern_const("after_output"));
4556 sym_incomplete_input = ID2SYM(rb_intern_const("incomplete_input"));
4557 sym_universal_newline = ID2SYM(rb_intern_const("universal_newline"));
4558 sym_crlf_newline = ID2SYM(rb_intern_const("crlf_newline"));
4559 sym_cr_newline = ID2SYM(rb_intern_const("cr_newline"));
4560 sym_lf_newline = ID2SYM(rb_intern("lf_newline"));
4561 sym_partial_input = ID2SYM(rb_intern_const("partial_input"));
4562
4563#ifdef ENABLE_ECONV_NEWLINE_OPTION
4564 sym_newline = ID2SYM(rb_intern_const("newline"));
4565 sym_universal = ID2SYM(rb_intern_const("universal"));
4566 sym_crlf = ID2SYM(rb_intern_const("crlf"));
4567 sym_cr = ID2SYM(rb_intern_const("cr"));
4568 sym_lf = ID2SYM(rb_intern_const("lf"));
4569#endif
4570
4571 InitVM(transcode);
4572}
4573
4574void
4575InitVM_transcode(void)
4576{
4577 rb_eUndefinedConversionError = rb_define_class_under(rb_cEncoding, "UndefinedConversionError", rb_eEncodingError);
4578 rb_eInvalidByteSequenceError = rb_define_class_under(rb_cEncoding, "InvalidByteSequenceError", rb_eEncodingError);
4579 rb_eConverterNotFoundError = rb_define_class_under(rb_cEncoding, "ConverterNotFoundError", rb_eEncodingError);
4580
4581 rb_define_method(rb_cString, "encode", str_encode, -1);
4582 rb_define_method(rb_cString, "encode!", str_encode_bang, -1);
4583
4584 rb_cEncodingConverter = rb_define_class_under(rb_cEncoding, "Converter", rb_cObject);
4585 rb_define_alloc_func(rb_cEncodingConverter, econv_s_allocate);
4586 rb_define_singleton_method(rb_cEncodingConverter, "asciicompat_encoding", econv_s_asciicompat_encoding, 1);
4587 rb_define_singleton_method(rb_cEncodingConverter, "search_convpath", econv_s_search_convpath, -1);
4588 rb_define_method(rb_cEncodingConverter, "initialize", econv_init, -1);
4589 rb_define_method(rb_cEncodingConverter, "inspect", econv_inspect, 0);
4590 rb_define_method(rb_cEncodingConverter, "convpath", econv_convpath, 0);
4591 rb_define_method(rb_cEncodingConverter, "source_encoding", econv_source_encoding, 0);
4592 rb_define_method(rb_cEncodingConverter, "destination_encoding", econv_destination_encoding, 0);
4593 rb_define_method(rb_cEncodingConverter, "primitive_convert", econv_primitive_convert, -1);
4594 rb_define_method(rb_cEncodingConverter, "convert", econv_convert, 1);
4595 rb_define_method(rb_cEncodingConverter, "finish", econv_finish, 0);
4596 rb_define_method(rb_cEncodingConverter, "primitive_errinfo", econv_primitive_errinfo, 0);
4597 rb_define_method(rb_cEncodingConverter, "insert_output", econv_insert_output, 1);
4598 rb_define_method(rb_cEncodingConverter, "putback", econv_putback, -1);
4599 rb_define_method(rb_cEncodingConverter, "last_error", econv_last_error, 0);
4600 rb_define_method(rb_cEncodingConverter, "replacement", econv_get_replacement, 0);
4601 rb_define_method(rb_cEncodingConverter, "replacement=", econv_set_replacement, 1);
4602 rb_define_method(rb_cEncodingConverter, "==", econv_equal, 1);
4603
4604 /*
4605 *Mask for invalid byte sequences
4606 */
4607 rb_define_const(rb_cEncodingConverter, "INVALID_MASK", INT2FIX(ECONV_INVALID_MASK));
4608
4609 /*
4610 * Replace invalid byte sequences
4611 */
4612 rb_define_const(rb_cEncodingConverter, "INVALID_REPLACE", INT2FIX(ECONV_INVALID_REPLACE));
4613
4614 /*
4615 * Mask for a valid character in the source encoding but no related
4616 * character(s) in destination encoding.
4617 */
4618 rb_define_const(rb_cEncodingConverter, "UNDEF_MASK", INT2FIX(ECONV_UNDEF_MASK));
4619
4620 /*
4621 * Replace byte sequences that are undefined in the destination encoding.
4622 */
4623 rb_define_const(rb_cEncodingConverter, "UNDEF_REPLACE", INT2FIX(ECONV_UNDEF_REPLACE));
4624
4625 /*
4626 * Replace byte sequences that are undefined in the destination encoding
4627 * with an XML hexadecimal character reference. This is valid for XML
4628 * conversion.
4629 */
4630 rb_define_const(rb_cEncodingConverter, "UNDEF_HEX_CHARREF", INT2FIX(ECONV_UNDEF_HEX_CHARREF));
4631
4632 /*
4633 * Indicates the source may be part of a larger string. See
4634 * primitive_convert for an example.
4635 */
4636 rb_define_const(rb_cEncodingConverter, "PARTIAL_INPUT", INT2FIX(ECONV_PARTIAL_INPUT));
4637
4638 /*
4639 * Stop converting after some output is complete but before all of the
4640 * input was consumed. See primitive_convert for an example.
4641 */
4642 rb_define_const(rb_cEncodingConverter, "AFTER_OUTPUT", INT2FIX(ECONV_AFTER_OUTPUT));
4643
4644 /*
4645 * Decorator for converting CRLF and CR to LF
4646 */
4647 rb_define_const(rb_cEncodingConverter, "UNIVERSAL_NEWLINE_DECORATOR", INT2FIX(ECONV_UNIVERSAL_NEWLINE_DECORATOR));
4648
4649 /*
4650 * Decorator for converting CRLF and CR to LF when writing
4651 */
4652 rb_define_const(rb_cEncodingConverter, "LF_NEWLINE_DECORATOR", INT2FIX(ECONV_LF_NEWLINE_DECORATOR));
4653
4654 /*
4655 * Decorator for converting LF to CRLF
4656 */
4657 rb_define_const(rb_cEncodingConverter, "CRLF_NEWLINE_DECORATOR", INT2FIX(ECONV_CRLF_NEWLINE_DECORATOR));
4658
4659 /*
4660 * Decorator for converting LF to CR
4661 */
4662 rb_define_const(rb_cEncodingConverter, "CR_NEWLINE_DECORATOR", INT2FIX(ECONV_CR_NEWLINE_DECORATOR));
4663
4664 /*
4665 * Escape as XML CharData
4666 */
4667 rb_define_const(rb_cEncodingConverter, "XML_TEXT_DECORATOR", INT2FIX(ECONV_XML_TEXT_DECORATOR));
4668
4669 /*
4670 * Escape as XML AttValue
4671 */
4672 rb_define_const(rb_cEncodingConverter, "XML_ATTR_CONTENT_DECORATOR", INT2FIX(ECONV_XML_ATTR_CONTENT_DECORATOR));
4673
4674 /*
4675 * Escape as XML AttValue
4676 */
4677 rb_define_const(rb_cEncodingConverter, "XML_ATTR_QUOTE_DECORATOR", INT2FIX(ECONV_XML_ATTR_QUOTE_DECORATOR));
4678
4679 rb_define_method(rb_eUndefinedConversionError, "source_encoding_name", ecerr_source_encoding_name, 0);
4680 rb_define_method(rb_eUndefinedConversionError, "destination_encoding_name", ecerr_destination_encoding_name, 0);
4681 rb_define_method(rb_eUndefinedConversionError, "source_encoding", ecerr_source_encoding, 0);
4682 rb_define_method(rb_eUndefinedConversionError, "destination_encoding", ecerr_destination_encoding, 0);
4683 rb_define_method(rb_eUndefinedConversionError, "error_char", ecerr_error_char, 0);
4684
4685 rb_define_method(rb_eInvalidByteSequenceError, "source_encoding_name", ecerr_source_encoding_name, 0);
4686 rb_define_method(rb_eInvalidByteSequenceError, "destination_encoding_name", ecerr_destination_encoding_name, 0);
4687 rb_define_method(rb_eInvalidByteSequenceError, "source_encoding", ecerr_source_encoding, 0);
4688 rb_define_method(rb_eInvalidByteSequenceError, "destination_encoding", ecerr_destination_encoding, 0);
4689 rb_define_method(rb_eInvalidByteSequenceError, "error_bytes", ecerr_error_bytes, 0);
4690 rb_define_method(rb_eInvalidByteSequenceError, "readagain_bytes", ecerr_readagain_bytes, 0);
4691 rb_define_method(rb_eInvalidByteSequenceError, "incomplete_input?", ecerr_incomplete_input, 0);
4692
4693 Init_newline();
4694}
ruby_coderange_type
What rb_enc_str_coderange() returns.
Definition coderange.h:33
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
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.
Definition class.c:3203
#define ECONV_XML_ATTR_QUOTE_DECORATOR
Old name of RUBY_ECONV_XML_ATTR_QUOTE_DECORATOR.
Definition transcode.h:539
#define ECONV_AFTER_OUTPUT
Old name of RUBY_ECONV_AFTER_OUTPUT.
Definition transcode.h:555
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1676
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
Definition coderange.h:180
#define ENC_CODERANGE_VALID
Old name of RUBY_ENC_CODERANGE_VALID.
Definition coderange.h:181
#define ECONV_UNIVERSAL_NEWLINE_DECORATOR
Old name of RUBY_ECONV_UNIVERSAL_NEWLINE_DECORATOR.
Definition transcode.h:532
#define ALLOC
Old name of RB_ALLOC.
Definition memory.h:400
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define OBJ_FROZEN
Old name of RB_OBJ_FROZEN.
Definition fl_type.h:133
#define ECONV_XML_ATTR_CONTENT_DECORATOR
Old name of RUBY_ECONV_XML_ATTR_CONTENT_DECORATOR.
Definition transcode.h:537
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1684
#define ECONV_INVALID_MASK
Old name of RUBY_ECONV_INVALID_MASK.
Definition transcode.h:523
#define ECONV_CRLF_NEWLINE_DECORATOR
Old name of RUBY_ECONV_CRLF_NEWLINE_DECORATOR.
Definition transcode.h:533
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:131
#define ECONV_UNDEF_REPLACE
Old name of RUBY_ECONV_UNDEF_REPLACE.
Definition transcode.h:526
#define ECONV_XML_TEXT_DECORATOR
Old name of RUBY_ECONV_XML_TEXT_DECORATOR.
Definition transcode.h:536
#define rb_ary_new4
Old name of rb_ary_new_from_values.
Definition array.h:659
#define ENC_CODERANGE_UNKNOWN
Old name of RUBY_ENC_CODERANGE_UNKNOWN.
Definition coderange.h:179
#define ECONV_CR_NEWLINE_DECORATOR
Old name of RUBY_ECONV_CR_NEWLINE_DECORATOR.
Definition transcode.h:534
#define xmalloc
Old name of ruby_xmalloc.
Definition xmalloc.h:53
#define ECONV_INVALID_REPLACE
Old name of RUBY_ECONV_INVALID_REPLACE.
Definition transcode.h:524
#define T_HASH
Old name of RUBY_T_HASH.
Definition value_type.h:65
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:399
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
Definition encoding.h:517
#define rb_exc_new3
Old name of rb_exc_new_str.
Definition error.h:38
#define ECONV_UNDEF_MASK
Old name of RUBY_ECONV_UNDEF_MASK.
Definition transcode.h:525
#define Qtrue
Old name of RUBY_Qtrue.
#define ECONV_PARTIAL_INPUT
Old name of RUBY_ECONV_PARTIAL_INPUT.
Definition transcode.h:554
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
#define ECONV_ERROR_HANDLER_MASK
Old name of RUBY_ECONV_ERROR_HANDLER_MASK.
Definition transcode.h:522
#define INT2NUM
Old name of RB_INT2NUM.
Definition int.h:43
#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.
Definition coderange.h:182
#define ECONV_LF_NEWLINE_DECORATOR
Old name of RUBY_ECONV_LF_NEWLINE_DECORATOR.
Definition transcode.h:535
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
Definition encoding.h:516
#define ECONV_UNDEF_HEX_CHARREF
Old name of RUBY_ECONV_UNDEF_HEX_CHARREF.
Definition transcode.h:527
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
#define ECONV_NEWLINE_DECORATOR_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_MASK.
Definition transcode.h:529
#define rb_ary_new2
Old name of rb_ary_new_capa.
Definition array.h:657
#define ENC_CODERANGE_SET(obj, cr)
Old name of RB_ENC_CODERANGE_SET.
Definition coderange.h:186
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition eval.c:676
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1431
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1429
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.
Definition error.c:1417
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.
Definition error.c:1482
VALUE rb_eEncodingError
EncodingError exception.
Definition error.c:1437
void rb_warning(const char *fmt,...)
Issues a warning.
Definition error.c:499
VALUE rb_cObject
Object class.
Definition object.c:60
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition object.c:234
VALUE rb_cEncoding
Encoding class.
Definition encoding.c:60
VALUE rb_cString
String class.
Definition string.c:85
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
Definition object.c:3326
Encoding relates APIs.
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
Encoding conversion main routine.
Definition string.c:1379
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.
Definition string.c:844
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.
Definition transcode.c:2664
VALUE rb_econv_open_exc(const char *senc, const char *denc, int ecflags)
Creates a rb_eConverterNotFoundError exception object (but does not raise).
Definition transcode.c:2124
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.
Definition transcode.c:1542
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_...
Definition transcode.c:2709
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.
Definition transcode.c:1485
rb_econv_result_t
return value of rb_econv_convert()
Definition transcode.h:30
@ econv_incomplete_input
The conversion stopped in middle of reading a character, possibly due to a partial read of a socket e...
Definition transcode.h:69
@ econv_finished
The conversion stopped after converting everything.
Definition transcode.h:57
@ econv_undefined_conversion
The conversion stopped when it found a character in the input which cannot be representable in the ou...
Definition transcode.h:41
@ econv_after_output
The conversion stopped after writing something to somewhere, before reading everything.
Definition transcode.h:63
@ econv_source_buffer_empty
The conversion stopped because there is no input.
Definition transcode.h:51
@ econv_destination_buffer_full
The conversion stopped because there is no destination.
Definition transcode.h:46
@ econv_invalid_byte_sequence
The conversion stopped when it found an invalid sequence.
Definition transcode.h:35
int rb_econv_putbackable(rb_econv_t *ec)
Queries if rb_econv_putback() makes sense, i.e.
Definition transcode.c:1781
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.
Definition transcode.c:3283
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.
Definition transcode.c:1106
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...
Definition transcode.c:1948
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...
Definition transcode.c:1939
const char * rb_econv_asciicompat_encoding(const char *encname)
Queries the passed encoding's corresponding ASCII compatible encoding.
Definition transcode.c:1825
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.
Definition transcode.c:1627
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.
Definition transcode.c:1960
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.
Definition transcode.c:2715
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.
Definition transcode.c:2006
void rb_econv_binmode(rb_econv_t *ec)
This badly named function does not set the destination encoding to binary, but instead just nullifies...
Definition transcode.c:2023
int rb_econv_decorate_at_first(rb_econv_t *ec, const char *decorator_name)
"Decorate"s a converter.
Definition transcode.c:1989
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.
Definition transcode.c:2978
VALUE rb_econv_make_exception(rb_econv_t *ec)
This function makes sense right after rb_econv_convert() returns.
Definition transcode.c:4344
void rb_econv_check_error(rb_econv_t *ec)
This is a rb_econv_make_exception() + rb_exc_raise() combo.
Definition transcode.c:4350
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.
Definition transcode.c:1954
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
Definition transcode.c:1742
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 ...
Definition transcode.c:1876
void rb_econv_putback(rb_econv_t *ec, unsigned char *p, int n)
Puts back the bytes.
Definition transcode.c:1792
int rb_econv_set_replacement(rb_econv_t *ec, const unsigned char *str, size_t len, const char *encname)
Assigns the replacement string.
Definition transcode.c:2287
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.
Definition vm_eval.c:1174
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.
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
Definition error.h:284
VALUE rb_proc_call(VALUE recv, VALUE args)
Evaluates the passed proc with the passed arguments.
Definition proc.c:1738
VALUE rb_obj_is_method(VALUE recv)
Queries if the given object is a method.
Definition proc.c:2454
VALUE rb_method_call(int argc, const VALUE *argv, VALUE recv)
Evaluates the passed method with the passed arguments.
Definition proc.c:3345
VALUE rb_obj_is_proc(VALUE recv)
Queries if the given object is a proc.
Definition proc.c:386
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
Definition string.c:1783
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1499
void rb_str_shared_replace(VALUE dst, VALUE src)
Replaces the contents of the former with the latter.
Definition string.c:1825
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
Definition string.c:1023
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
Definition string.c:1555
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:2023
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
Definition string.c:3485
void rb_str_modify_expand(VALUE str, long capa)
Identical to rb_str_modify(), except it additionally expands the capacity of the receiver.
Definition string.c:2801
VALUE rb_str_dump(VALUE str)
"Inverse" of rb_eval_string().
Definition string.c:7942
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
Definition string.c:1755
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1515
VALUE rb_str_drop_bytes(VALUE str, long len)
Shrinks the given string for the given number of bytes.
Definition string.c:5839
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.
Definition variable.c:2060
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
Definition vm_method.c:3590
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:285
VALUE rb_sym2str(VALUE symbol)
Obtain a frozen string representation of a symbol (not including the leading colon).
Definition symbol.c:1148
int off
Offset inside of ptr.
Definition io.h:5
int len
Length of the buffer.
Definition io.h:8
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
Definition memory.h:372
#define ALLOCA_N(type, n)
Definition memory.h:292
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
Definition memory.h:384
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:50
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition rarray.h:280
#define RARRAY_AREF(a, i)
Definition rarray.h:402
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
static char * RSTRING_END(VALUE str)
Queries the end of the contents pointer of the string.
Definition rstring.h:409
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:89
#define TypedData_Get_Struct(obj, type, data_type, sval)
Obtains a C struct from inside of a wrapper Ruby object.
Definition rtypeddata.h:773
#define DATA_PTR(obj)
Convenient casting macro for backward compatibility.
Definition rtypeddata.h:435
#define TypedData_Wrap_Struct(klass, data_type, sval)
Converts sval, a pointer to your struct, into a Ruby object.
Definition rtypeddata.h:557
const char * rb_obj_classname(VALUE obj)
Queries the name of the class of the passed object.
Definition variable.c:530
#define InitVM(ext)
This macro is for internal use.
Definition ruby.h:231
#define RTEST
This is an old name of RB_TEST.
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:238
Definition st.h:79
Definition string.c:8866
Definition transcode.c:179
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:376