summaryrefslogtreecommitdiffstats
path: root/transcode.c
diff options
context:
space:
mode:
authorakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-08-14 06:35:33 +0000
committerakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-08-14 06:35:33 +0000
commit83d2bb4bf3a4e63e65b4356fa59d2ba28a8a3c60 (patch)
tree94f84e5fb9b24f31231c4911c8939476440b3e24 /transcode.c
parentbd22699a0757a06ac0ea4c0409241d9e5fab478d (diff)
downloadruby-83d2bb4bf3a4e63e65b4356fa59d2ba28a8a3c60.tar.gz
ruby-83d2bb4bf3a4e63e65b4356fa59d2ba28a8a3c60.tar.xz
ruby-83d2bb4bf3a4e63e65b4356fa59d2ba28a8a3c60.zip
* transcode.c (rb_econv_conv): new function. it don't consume input
too much, even for multilevel conversion. (transcode_loop): use rb_econv_conv. (econv_primitive_convert): ditto. git-svn-id: http://svn.ruby-lang.org/repos/ruby/trunk@18610 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'transcode.c')
-rw-r--r--transcode.c33
1 files changed, 28 insertions, 5 deletions
diff --git a/transcode.c b/transcode.c
index 78d6b2582..91c67d0e7 100644
--- a/transcode.c
+++ b/transcode.c
@@ -955,6 +955,25 @@ found_needreport:
return transcode_ibuf_empty;
}
+static rb_trans_result_t
+rb_econv_conv(rb_trans_t *ts,
+ const unsigned char **input_ptr, const unsigned char *input_stop,
+ unsigned char **output_ptr, unsigned char *output_stop,
+ int flags)
+{
+ rb_trans_result_t res;
+
+ if ((flags & OUTPUT_FOLLOWED_BY_INPUT) ||
+ ts->num_trans == 1)
+ return rb_trans_conv(ts, input_ptr, input_stop, output_ptr, output_stop, flags);
+
+ flags |= OUTPUT_FOLLOWED_BY_INPUT;
+ do {
+ res = rb_trans_conv(ts, input_ptr, input_stop, output_ptr, output_stop, flags);
+ } while (res == transcode_output_followed_by_input);
+ return res;
+}
+
static void
rb_trans_close(rb_trans_t *ts)
{
@@ -1064,7 +1083,7 @@ transcode_loop(const unsigned char **in_pos, unsigned char **out_pos,
max_output = last_tc->transcoder->max_output;
resume:
- ret = rb_trans_conv(ts, in_pos, in_stop, out_pos, out_stop, opt);
+ ret = rb_econv_conv(ts, in_pos, in_stop, out_pos, out_stop, opt);
if (ret == transcode_invalid_input) {
/* deal with invalid byte sequence */
/* todo: add more alternative behaviors */
@@ -1134,14 +1153,14 @@ transcode_loop(const unsigned char **in_pos, unsigned char **out_pos,
if (ret == transcode_ibuf_empty) {
if (ptr < in_stop) {
input_byte = *ptr;
- ret = rb_trans_conv(ts, &p, p+1, out_pos, out_stop, PARTIAL_INPUT);
+ ret = rb_econv_conv(ts, &p, p+1, out_pos, out_stop, PARTIAL_INPUT);
}
else {
- ret = rb_trans_conv(ts, NULL, NULL, out_pos, out_stop, 0);
+ ret = rb_econv_conv(ts, NULL, NULL, out_pos, out_stop, 0);
}
}
else {
- ret = rb_trans_conv(ts, NULL, NULL, out_pos, out_stop, PARTIAL_INPUT);
+ ret = rb_econv_conv(ts, NULL, NULL, out_pos, out_stop, PARTIAL_INPUT);
}
if (&input_byte != p)
ptr += p - &input_byte;
@@ -1495,10 +1514,12 @@ check_econv(VALUE self)
*
* possible flags:
* Encoding::Converter::PARTIAL_INPUT # input buffer may be part of larger input
+ * Encoding::Converter::OUTPUT_FOLLOWED_BY_INPUT # stop conversion after output before input
*
* possible results:
* :invalid_input
* :undefined_conversion
+ * :output_followed_by_input
* :obuf_full
* :ibuf_empty
* :finished
@@ -1527,6 +1548,8 @@ check_econv(VALUE self)
* primitive_convert stops conversion when one of following condition met.
* - invalid byte sequence found in input buffer (:invalid_input)
* - character not representable in output encoding (:undefined_conversion)
+ * - after some output is generated, before any input is consumed (:output_followed_by_input)
+ * this occur only when OUTPUT_FOLLOWED_BY_INPUT is specified.
* - output buffer is full (:obuf_full)
* - input buffer is empty (:ibuf_empty)
* this occur only when PARTIAL_INPUT is specified.
@@ -1606,7 +1629,7 @@ econv_primitive_convert(int argc, VALUE *argv, VALUE self)
op = (unsigned char *)RSTRING_PTR(output) + output_byteoffset;
os = op + output_bytesize;
- res = rb_trans_conv(ts, &ip, is, &op, os, flags);
+ res = rb_econv_conv(ts, &ip, is, &op, os, flags);
rb_str_set_len(output, op-(unsigned char *)RSTRING_PTR(output));
rb_str_drop_bytes(input, ip - (unsigned char *)RSTRING_PTR(input));