--- dovecot-2.0-pure/src/lib/istream-crlf.c 2010-08-08 10:05:33.000000000 +0200 +++ dovecot-2.0/src/lib/istream-crlf.c 2010-08-30 15:22:20.000000000 +0200 @@ -39,7 +39,8 @@ { struct crlf_istream *cstream = (struct crlf_istream *)stream; const unsigned char *data; - size_t i, dest, size; + unsigned char *s_ptr, *s_end, *d_ptr, *d_end, *ptr; + size_t size, cpy_len; ssize_t ret; ret = i_stream_crlf_read_common(cstream); @@ -49,27 +50,61 @@ data = i_stream_get_data(stream->parent, &size); /* @UNSAFE: add missing CRs */ - dest = stream->pos; - for (i = 0; i < size && dest < stream->buffer_size; i++) { - if (data[i] == '\n') { - if (i == 0) { - if (!cstream->last_cr) - stream->w_buffer[dest++] = '\r'; - } else { - if (data[i-1] != '\r') - stream->w_buffer[dest++] = '\r'; - } - if (dest == stream->buffer_size) - break; + d_ptr = stream->w_buffer + stream->pos; + d_end = stream->w_buffer + stream->buffer_size; + s_ptr = (unsigned char *)data; + s_end = (unsigned char *)data + size; + + if (s_ptr < s_end && *s_ptr == '\n' && !cstream->last_cr && d_ptr < d_end) { + *(d_ptr++) = '\r'; + + if (d_ptr < d_end) { + *(d_ptr++) = '\n'; + s_ptr++; } - stream->w_buffer[dest++] = data[i]; } - cstream->last_cr = stream->w_buffer[dest-1] == '\r'; - i_stream_skip(stream->parent, i); - ret = dest - stream->pos; + while (d_ptr < d_end) { + ptr = memchr(s_ptr, '\n', s_end - s_ptr); + if (ptr == NULL) + ptr = s_end; + + cpy_len = ptr - s_ptr; + if (d_ptr + cpy_len > d_end) + cpy_len = d_end - d_ptr; + + if (cpy_len > 0) { + memcpy(d_ptr, s_ptr, cpy_len); + + d_ptr += cpy_len; + s_ptr += cpy_len; + } + + i_assert(d_ptr <= d_end && s_ptr <= s_end); + if (d_ptr == d_end || s_ptr == s_end) + break; + + if (*(s_ptr - 1) != '\r') + *(d_ptr++) = '\r'; + + if (d_ptr < d_end) { + *(d_ptr++) = '\n'; + s_ptr++; + } + + i_assert(s_ptr == ptr + 1); + } + + cstream->last_cr = *(d_ptr - 1) == '\r'; + i_stream_skip(stream->parent, s_ptr - data); + + ret = (d_ptr - stream->w_buffer) - stream->pos; i_assert(ret > 0); - stream->pos = dest; + stream->pos = d_ptr - stream->w_buffer; return ret; }