From 9aefcae16c1e716039ddf8e1921e3a6be9635277 Mon Sep 17 00:00:00 2001 From: Bertrand Guiheneuf Date: Mon, 28 Feb 2000 13:36:46 +0000 Subject: non blocking b64 encoding is a PITA svn path=/trunk/; revision=1974 --- camel/ChangeLog | 16 +++ camel/camel-stream-b64.c | 335 +++++++++++++++++++++++++++++++++++++++-------- camel/camel-stream-b64.h | 16 ++- 3 files changed, 308 insertions(+), 59 deletions(-) diff --git a/camel/ChangeLog b/camel/ChangeLog index 0a45793135..c7ef60b391 100644 --- a/camel/ChangeLog +++ b/camel/ChangeLog @@ -1,3 +1,19 @@ +2000-02-28 bertrand + + * camel-stream-b64.c (my_read_encode): encoding + filter. + +2000-02-23 bertrand + + * camel-stream-b64.c: changed the __static + suffix into a my_ prefix. + (camel_stream_b64_set_mode): reset the persistent + status. + (my_read_decode): remove superfluous % + + * providers/mbox/camel-mbox-utils.c (camel_mbox_copy_file_chunk): + fix exception description message. + 2000-02-24 Dan Winship * camel-session.c: Add camel_session_get_transport_for_protocol. diff --git a/camel/camel-stream-b64.c b/camel/camel-stream-b64.c index 3b97b11aad..000557ae82 100644 --- a/camel/camel-stream-b64.c +++ b/camel/camel-stream-b64.c @@ -26,6 +26,7 @@ #include #include "camel-stream-b64.h" +#define BSIZE 512 @@ -73,37 +74,40 @@ static gchar six_bits_to_char[65] = /* Returns the class for a CamelStreamB64 */ #define CSB64_CLASS(so) CAMEL_STREAM_B64_CLASS (GTK_OBJECT(so)->klass) -static void init_with_input_stream__static (CamelStreamB64 *stream_b64, - CamelStream *input_stream); +static void my_init_with_input_stream (CamelStreamB64 *stream_b64, + CamelStream *input_stream); -static gint read__static (CamelStream *stream, - gchar *buffer, - gint n); +static gint my_read (CamelStream *stream, + gchar *buffer, + gint n); -static void reset__static (CamelStream *stream); +static void my_reset (CamelStream *stream); -static gint read_decode__static (CamelStream *stream, - gchar *buffer, - gint n); -static gboolean eos__static (CamelStream *stream); +static gint my_read_decode (CamelStream *stream, + gchar *buffer, + gint n); +static gint my_read_encode (CamelStream *stream, + gchar *buffer, + gint n); +static gboolean my_eos (CamelStream *stream); static void camel_stream_b64_class_init (CamelStreamB64Class *camel_stream_b64_class) { CamelStreamClass *camel_stream_class = CAMEL_STREAM_CLASS (camel_stream_b64_class); - - + + parent_class = gtk_type_class (camel_stream_get_type ()); - + /* virtual method definition */ - camel_stream_b64_class->init_with_input_stream = init_with_input_stream__static; - - + camel_stream_b64_class->init_with_input_stream = my_init_with_input_stream; + + /* virtual method overload */ - camel_stream_class->read = read__static; - camel_stream_class->eos = eos__static; - camel_stream_class->reset = reset__static; - + camel_stream_class->read = my_read; + camel_stream_class->eos = my_eos; + camel_stream_class->reset = my_reset; + /* signal definition */ } @@ -133,29 +137,28 @@ camel_stream_b64_get_type (void) } -static void -reemit_available_signal__static (CamelStream *parent_stream, gpointer user_data) +static void +my_reemit_available_signal (CamelStream *parent_stream, gpointer user_data) { gtk_signal_emit_by_name (GTK_OBJECT (user_data), "data_available"); } static void -init_with_input_stream__static (CamelStreamB64 *stream_b64, - CamelStream *input_stream) +my_init_with_input_stream (CamelStreamB64 *stream_b64, + CamelStream *input_stream) { g_assert (stream_b64); g_assert (input_stream); - - + + /* by default, the stream is in decode mode */ stream_b64->mode = CAMEL_STREAM_B64_DECODER; - - stream_b64->eos = FALSE; - stream_b64->decode_status.keep = 0; - stream_b64->decode_status.state = 0; - + stream_b64->eos = FALSE; + stream_b64->status.decode_status.keep = 0; + stream_b64->status.decode_status.state = 0; + stream_b64->input_stream = input_stream; gtk_object_ref (GTK_OBJECT (input_stream)); @@ -168,14 +171,14 @@ init_with_input_stream__static (CamelStreamB64 *stream_b64, */ gtk_signal_connect (GTK_OBJECT (input_stream), "data_available", - reemit_available_signal__static, + my_reemit_available_signal, stream_b64); /* bootstrapping signal */ gtk_signal_emit_by_name (GTK_OBJECT (stream_b64), "data_available"); - - + + } @@ -199,33 +202,45 @@ camel_stream_b64_set_mode (CamelStreamB64 *stream_b64, CamelStreamB64Mode mode) { g_assert (stream_b64); + stream_b64->mode = mode; + + if (mode == CAMEL_STREAM_B64_DECODER) { + stream_b64->status.decode_status.keep = 0; + stream_b64->status.decode_status.state = 0; + } else { + stream_b64->status.encode_status.keep = 0; + stream_b64->status.encode_status.state = 0; + stream_b64->status.encode_status.end_state = 0; + } + } static gint -read__static (CamelStream *stream, - gchar *buffer, - gint n) +my_read (CamelStream *stream, + gchar *buffer, + gint n) { CamelStreamB64 *stream_b64 = CAMEL_STREAM_B64 (stream); g_assert (stream); - - if (stream_b64->mode == CAMEL_STREAM_B64_DECODER) - return read_decode__static (stream, buffer, n); - return 0; + if (stream_b64->mode == CAMEL_STREAM_B64_DECODER) + return my_read_decode (stream, buffer, n); + else + return my_read_encode (stream, buffer, n); } -static gint read_decode__static (CamelStream *stream, - gchar *buffer, - gint n) +static gint +my_read_decode (CamelStream *stream, + gchar *buffer, + gint n) { CamelStreamB64 *stream_b64 = CAMEL_STREAM_B64 (stream); CamelStream64DecodeStatus *status; @@ -237,14 +252,11 @@ static gint read_decode__static (CamelStream *stream, g_assert (stream); input_stream = stream_b64->input_stream; - - g_assert (input_stream); - status = &(stream_b64->decode_status); + g_assert (input_stream); + status = &(stream_b64->status.decode_status); - /* state = (CamelStream64DecodeState *) - ((gchar *)stream_b64 + G_STRUCT_OFFSET (CamelStreamB64, decode_state)) */ - + nb_read_in_input = camel_stream_read (input_stream, &c, 1); while ((nb_read_in_input >0 ) && (jstate % 4){ + switch (status->state){ case 0: status->keep = six_bits_value << 2; @@ -296,20 +308,223 @@ static gint read_decode__static (CamelStream *stream, } +static gint +my_read_encode (CamelStream *stream, + gchar *buffer, + gint n) +{ + CamelStreamB64 *stream_b64 = CAMEL_STREAM_B64 (stream); + CamelStream64EncodeStatus *status; + CamelStream *input_stream; + gint nb_read_in_input = 0; + guchar c; + gint j = 0; + gboolean end_of_read = FALSE; + + g_assert (stream); + input_stream = stream_b64->input_stream; + + g_assert (input_stream); + + /* I don't know why the caller would want to + read a zero length buffer but ... */ + if (n == 0) + return 0; + + + status = &(stream_b64->status.encode_status); + + + if (status->end_state == 0) { + /* we are not at the end of the input steam, + process the data normally */ + + while ((jline_length == 76) { + buffer [j++] = '\n'; + status->line_length = 0; + break; + } + + /* + * because we encode four characters for + * 3 bytes, the last char does not need any + * read to write in the stream + */ + if (status->state == 3) { + buffer [j++] = status->keep; + status->keep = 0; + status->line_length++; + break; + } + + /* + * in all the other phases of the stream + * writing, we need to read a byte from the + * input stream + */ + nb_read_in_input = camel_stream_read (input_stream, &c, 1); + + if (nb_read_in_input > 0) { + switch (status->state){ + + case 0: + buffer [j++] = six_bits_to_char [c >> 2]; + status->keep = (c & 0xc0 ) >> 2; + break; + + case 1: + buffer [j++] = six_bits_to_char [status->keep | (c >> 4)]; + status->keep = (c & 0x0f ) << 2; + break; + + case 2: + buffer [j++] = six_bits_to_char [status->keep | (c >> 6)] ; + status->keep = (c & 0x3f ); + break; + + } + + status->state = (status->state + 1) % 4; + status->line_length++; + } else + end_of_read = TRUE; + + + if (camel_stream_eos (input_stream)) + status->end_state = 1; + + } + } + + /* + * now comes the real annoying part. Because some clients + * expect the b64 encoded sequence length to be multiple of 4, + * we must pad the end with '='. + * This is trivial when we write to stream as much as we want + * but this is not the case when we are limited in the number + * of chars we can write to the output stream. The consequence + * of this is that we must keep the state of the writing + * so that we can resume the next time this routine is called. + */ + if ( status->end_state != 0) { + + /* + * we are at the end of the input stream + * we must pad the output with '='. + */ + while ((jend_state != 6)) { + + if (status->end_state == 5) { + status->end_state = 6; + buffer [j++] = '\n'; + stream->eos = TRUE; +; + } else { + + switch (status->state) { + + /* + * depending on state of the decoder, we need to + * write different things. + */ + case 0: + /* + * everyting has been written already and the + * output length is already a multiple of 3 + * so that we have nothing to do. + */ + status->end_state = 5; + break; + + case 1: + /* + * we have something in keep + * and two '=' we must write + */ + switch (status->end_state) { + case 1: + buffer [j++] = six_bits_to_char [status->keep] ; + status->end_state++; + break; + case 2: + buffer [j++] = '='; + status->end_state++; + break; + case 3: + buffer [j++] = '='; + status->end_state = 5; + break; + } + + + status->end_state++; + break; + + + case 2: + /* + * we have something in keep + * and one '=' we must write + */ + switch (status->end_state) { + case 1: + buffer [j++] = six_bits_to_char [status->keep]; + status->end_state++; + break; + case 2: + buffer [j++] = '='; + status->end_state = 5; + break; + } + + break; + + case 3: + /* + * we have something in keep we must write + */ + switch (status->end_state) { + case 1: + buffer [j++] = six_bits_to_char [status->keep]; + status->end_state++; + break; + case 2: + buffer [j++] = '='; + status->end_state = 5; + break; + } + + break; + } + + + } + } + + } + return j; +} + + + + static gboolean -eos__static (CamelStream *stream) +my_eos (CamelStream *stream) { CamelStreamB64 *stream_b64 = CAMEL_STREAM_B64 (stream); g_assert (stream); g_assert (stream_b64->input_stream); - - return (stream_b64->eos || camel_stream_eos (stream_b64->input_stream)); + + return (stream_b64->eos); } @@ -317,15 +532,19 @@ eos__static (CamelStream *stream) static void -reset__static (CamelStream *stream) +my_reset (CamelStream *stream) { CamelStreamB64 *stream_b64 = CAMEL_STREAM_B64 (stream); g_assert (stream); g_assert (stream_b64->input_stream); - - stream_b64->decode_status.keep = 0; - stream_b64->decode_status.state = 0; + + stream_b64->status.decode_status.keep = 0; + stream_b64->status.decode_status.state = 0; camel_stream_reset (stream_b64->input_stream); } + + + + diff --git a/camel/camel-stream-b64.h b/camel/camel-stream-b64.h index 0577d03f3f..23ad7d39b2 100644 --- a/camel/camel-stream-b64.h +++ b/camel/camel-stream-b64.h @@ -59,6 +59,20 @@ typedef struct { } CamelStream64DecodeStatus; +typedef struct { + + guchar state; + guchar keep; + guchar end_state; + guchar line_length; + +} CamelStream64EncodeStatus; + + +typedef union { + CamelStream64DecodeStatus decode_status; + CamelStream64EncodeStatus encode_status; +} CamelStream64Status; typedef struct { @@ -71,7 +85,7 @@ typedef struct gboolean eos; /* decoding status */ - CamelStream64DecodeStatus decode_status; + CamelStream64Status status; } CamelStreamB64; -- cgit v1.2.3