views:

116

answers:

3

Hi, I've seen the following code, taken from the libb64 project. I'm trying to understand what is the purpose of the while loop within the switch block -

switch (state_in->step)
    {
        while (1)
        {
    case step_a:
            do {
                if (codechar == code_in+length_in)
                {
                    state_in->step = step_a;
                    state_in->plainchar = *plainchar;
                    return plainchar - plaintext_out;
                }
                fragment = (char)base64_decode_value(*codechar++);
            } while (fragment < 0);
            *plainchar    = (fragment & 0x03f) << 2;
    case step_b:
            do {
                if (codechar == code_in+length_in)
                {
                    state_in->step = step_b;
                    state_in->plainchar = *plainchar;
                    return plainchar - plaintext_out;
                }
                fragment = (char)base64_decode_value(*codechar++);
            } while (fragment < 0);
            *plainchar++ |= (fragment & 0x030) >> 4;
            *plainchar    = (fragment & 0x00f) << 4;
    case step_c:
            do {
                if (codechar == code_in+length_in)
                {
                    state_in->step = step_c;
                    state_in->plainchar = *plainchar;
                    return plainchar - plaintext_out;
                }
                fragment = (char)base64_decode_value(*codechar++);
            } while (fragment < 0);
            *plainchar++ |= (fragment & 0x03c) >> 2;
            *plainchar    = (fragment & 0x003) << 6;
    case step_d:
            do {
                if (codechar == code_in+length_in)
                {
                    state_in->step = step_d;
                    state_in->plainchar = *plainchar;
                    return plainchar - plaintext_out;
                }
                fragment = (char)base64_decode_value(*codechar++);
            } while (fragment < 0);
            *plainchar++   |= (fragment & 0x03f);
        }
    }

What can give the while? It seems that anyway, always the switch will perform only one of the cases. Did I miss something?

Thanks.

+3  A: 

Like Kenny says, this code looks like a Duff's device. Here is what Wikipedia says about it.

vpit3833
A: 

If it's an attempt of implementing a Duff's device, then it's probably misplaced.

Note that in the case of Duff's device, as described in Wikipedia, the loop is finite, while in the code presented above it's a neverending loop. The only possibility for it to finish is satisfaction of the (codechar == code_in+length_in) condition (code_id and length_in are immutable in the code snippet, though).

I doubt it will even work as a Duff's device, i.e. that it will result in proper loop expansion by the compiler.

deemoowoor
+3  A: 

Although this is Duff's Device, this version is not about implementing a loop-unrolling optimisation but rather to implement an iterator over a Base64 encoded stream. So you can do something like this:

Base64Stream stream; // the base64 data

char c;

while ((c == stream->NextChar ()) != 0)
{
  // do something with c
}

In the given code, the first switch us used to jump back to where the previous return exited, and then the while (1) allows the iteration loop to continue indefinately. However, there's no protection against a buffer overrun in this function.

In C#, there is a neater solution to this, the yield statement.

Skizz