On Saturday, 13 December 2014 at 10:09:27 UTC, Charles Hixson via Digitalmars-d-learn wrote:
Is there a standard way to do this? The code below is untested, as I haven't yet written the x7to8 routine, and came up with a better way to do what this was to accomplish, but it feels as if this should be somewhere in the standard library, if I could only find it.

/** Repack the data from an array of ubytes into an array of ubytes of * which only the last 7 are significant. The high bit will be set only
 * if the byte would otherwise be zero.    */
byte[]    x8to7 (ubyte[] bin)
{
    ubyte[] bout;
    //    bit masks:    0 => 0xfe = 11111110, 0x00 = 00000000
    //                1 => 0x7f = 01111111, 0x00 = 00000000
    //                2 => 0x3f = 00111111, 0x80 = 10000000
    //                3 => 0x1f = 00011111, 0xc0 = 11000000
    //                4 => 0x0f = 00001111, 0xe0 = 11100000
    //                5 => 0x07 = 00000111, 0xf0 = 11110000
    //                6 => 0x03 = 00000011, 0xf8 = 11111000
    //                7 => 0x01 = 00000001, 0xfc = 11111100
    if (bin.length < 1)    return    bout;
    int    fByte, fBit;
    while    (fByte < bin.length)
    {    if (fByte + 1 == bin.length && fBit > 1)  break;
        ubyte    b;
        switch (fBit)
        {    case    0:
                b    =    bin[fByte]    / 2;
                break;
            case    1:
                b    =    bin[fByte] & 0x7f;
                break;
            case    2:
                ubyte    b1    =    (bin[fByte] & 0x3f) << 1;
ubyte b2 = (bin[fByte + 1] & 0x80) >>> 7;
                b    ~=    (b1 | b2);
                break;
            case    3:
                ubyte    b1    =    (bin[fByte] & 0x1f) << 2;
ubyte b2 = (bin[fByte + 1] & 0xc0) >>> 6;
                b    ~= (b1 | b2);
                break;
            case    4:
                ubyte    b1    =    (bin[fByte] & 0x0f) << 3;
ubyte b2 = (bin[fByte + 1] & 0xe0) >>> 5;
                b    ~= (b1 | b2);
                break;
            case    5:
                ubyte    b1    =    (bin[fByte] & 0x07) << 4;
ubyte b2 = (bin[fByte + 1] & 0xf0) >>> 4;
                b    ~= (b1 | b2);
                break;
            case    6:
                ubyte    b1    =    (bin[fByte] & 0x03) << 5;
ubyte b2 = (bin[fByte + 1] & 0xf8) >>> 3;
                b    ~= (b1 | b2);
                break;
            case    7:
                ubyte    b1    =    (bin[fByte] & 0x01) << 6;
ubyte b2 = (bin[fByte + 1] & 0xfc) >>> 2;
                b    ~= (b1 | b2);
                break;
            default:
assert (false, "This path should never be taken");
        }    //    switch (fBit)
        if    (b == 0)    bout    ~=    0x80;
        else            bout    ~=    b;
        fBit    =    fBit + 7;
        if    (fBit > 7)
        {    fByte++;
            fBit -=    7;
        }
    }
}

Are you trying to make a "kind-of" Variable-Length quantity encoder ?

eg:
0b10101110: last bit not set, integrate 0b10101110 and stop reading. 0b10011001: last bit set, integrate 0b10011000 and continue to next byte.

http://en.wikipedia.org/wiki/Variable-length_quantity

except that this algo limits the length to 24 bits. It was used a lot with MIDI, at a time when hardware memory was costly (eg inside hardware synthesizer or workstations).

Reply via email to