You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
171 lines
4.2 KiB
171 lines
4.2 KiB
3 months ago
|
/*
|
||
|
* UCW Library -- Base 224 Encoding & Decoding
|
||
|
*
|
||
|
* (c) 2002 Martin Mares <mj@ucw.cz>
|
||
|
*
|
||
|
* The `base-224' encoding transforms general sequences of bytes
|
||
|
* to sequences of non-control 8-bit characters (0x20-0xff). Since
|
||
|
* 224 and 256 are incompatible bases (there is no k,l: 224^k=256^l)
|
||
|
* and we want to avoid lengthy calculations, we cheat a bit:
|
||
|
*
|
||
|
* Each base-224 digit can be represented as a (base-7 digit, base-32 digit)
|
||
|
* pair, so we pass the lower 5 bits directly and use a base-7 encoder
|
||
|
* for the upper part. We process blocks of 39 bits and encode them
|
||
|
* to 5 base-224 digits: we take 5x5 bits as the lower halves and convert
|
||
|
* the remaining 14 bits in base-7 (2^14 = 16384 < 16807 = 7^5) to get
|
||
|
* the 7 upper parts we need (with a little redundancy). Little endian
|
||
|
* ordering is used to make handling of partial blocks easy.
|
||
|
*
|
||
|
* We transform 39 source bits to 40 destination bits, stretching the data
|
||
|
* by 1/39 = approx. 2.56%.
|
||
|
*
|
||
|
* This software may be freely distributed and used according to the terms
|
||
|
* of the GNU Lesser General Public License.
|
||
|
*/
|
||
|
|
||
|
#undef LOCAL_DEBUG
|
||
|
|
||
|
#include <ucw/lib.h>
|
||
|
#include <ucw/base224.h>
|
||
|
|
||
|
static void
|
||
|
encode_block(byte *w, u32 hi, u32 lo)
|
||
|
{
|
||
|
uint x, y;
|
||
|
|
||
|
/*
|
||
|
* Splitting of the 39-bit block: [a-e][0-5] are the base-32 digits, *'s are used for base-7.
|
||
|
* +----------------+----------------+----------------+----------------+----------------+
|
||
|
* +00******e4e3e2e1|e0******d4d3d2d1|d0******c4c3c2c1|c0******b4b3b2b1|b0****a4a3a2a1a0|
|
||
|
* +----------------+----------------+----------------+----------------+----------------+
|
||
|
*/
|
||
|
|
||
|
w[0] = lo & 0x1f;
|
||
|
w[1] = (lo >> 7) & 0x1f;
|
||
|
w[2] = (lo >> 15) & 0x1f;
|
||
|
w[3] = (lo >> 23) & 0x1f;
|
||
|
w[4] = (lo >> 31) | ((hi << 1) & 0x1e);
|
||
|
x = (lo >> 5) & 0x0003
|
||
|
| (lo >> 10) & 0x001c
|
||
|
| (lo >> 15) & 0x00e0
|
||
|
| (lo >> 20) & 0x0700
|
||
|
| (hi << 7) & 0x3800;
|
||
|
DBG("<<< h=%08x l=%08x x=%d", hi, lo, x);
|
||
|
for (y=0; y<5; y++)
|
||
|
{
|
||
|
w[y] += 0x20 + ((x % 7) << 5);
|
||
|
x /= 7;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
uint
|
||
|
base224_encode(byte *dest, const byte *src, uint len)
|
||
|
{
|
||
|
u32 lo=0, hi=0; /* 64-bit buffer accumulating input bits */
|
||
|
uint i=0; /* How many source bits do we have buffered */
|
||
|
u32 x;
|
||
|
byte *w=dest;
|
||
|
|
||
|
while (len--)
|
||
|
{
|
||
|
x = *src++;
|
||
|
if (i < 32)
|
||
|
{
|
||
|
lo |= x << i;
|
||
|
if (i > 24)
|
||
|
hi |= x >> (32-i);
|
||
|
}
|
||
|
else
|
||
|
hi |= x << (i-32);
|
||
|
i += 8;
|
||
|
if (i >= 39)
|
||
|
{
|
||
|
encode_block(w, hi, lo);
|
||
|
w += 5;
|
||
|
lo = hi >> 7;
|
||
|
hi = 0;
|
||
|
i -= 39;
|
||
|
}
|
||
|
}
|
||
|
if (i) /* Partial block */
|
||
|
{
|
||
|
encode_block(w, hi, lo);
|
||
|
w += (i+8)/8; /* Just check logarithms if you want to understand */
|
||
|
}
|
||
|
return w - dest;
|
||
|
}
|
||
|
|
||
|
uint
|
||
|
base224_decode(byte *dest, const byte *src, uint len)
|
||
|
{
|
||
|
u32 hi=0, lo=0; /* 64-bit buffer accumulating output bits */
|
||
|
uint i=0; /* How many bits do we have accumulated */
|
||
|
u32 h, l; /* Decoding of the current block */
|
||
|
uint x; /* base-7 part of the current block */
|
||
|
uint len0;
|
||
|
byte *start = dest;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
if (!len)
|
||
|
break;
|
||
|
len0 = len;
|
||
|
|
||
|
ASSERT(*src >= 0x20); /* byte 0 */
|
||
|
h = 0;
|
||
|
l = *src & 0x1f;
|
||
|
x = (*src++ >> 5) - 1;
|
||
|
if (!--len)
|
||
|
goto blockend;
|
||
|
|
||
|
ASSERT(*src >= 0x20); /* byte 1 */
|
||
|
l |= (*src & 0x1f) << 7;
|
||
|
x += ((*src++ >> 5) - 1) * 7;
|
||
|
if (!--len)
|
||
|
goto blockend;
|
||
|
|
||
|
ASSERT(*src >= 0x20); /* byte 2 */
|
||
|
l |= (*src & 0x1f) << 15;
|
||
|
x += ((*src++ >> 5) - 1) * 7*7;
|
||
|
if (!--len)
|
||
|
goto blockend;
|
||
|
|
||
|
ASSERT(*src >= 0x20); /* byte 3 */
|
||
|
l |= (*src & 0x1f) << 23;
|
||
|
x += ((*src++ >> 5) - 1) * 7*7*7;
|
||
|
if (!--len)
|
||
|
goto blockend;
|
||
|
|
||
|
ASSERT(*src >= 0x20); /* byte 4 */
|
||
|
l |= *src << 31;
|
||
|
h = (*src & 0x1f) >> 1;
|
||
|
x += ((*src++ >> 5) - 1) * 7*7*7*7;
|
||
|
--len;
|
||
|
|
||
|
blockend:
|
||
|
len0 -= len;
|
||
|
l |= ((x & 0x0003) << 5) /* Decode base-7 */
|
||
|
| ((x & 0x001c) << 10)
|
||
|
| ((x & 0x00e0) << 15)
|
||
|
| ((x & 0x0700) << 20);
|
||
|
h |= (x & 0x3800) >> 7;
|
||
|
|
||
|
DBG("<<< i=%d h=%08x l=%08x x=%d len0=%d", i, h, l, x, len0);
|
||
|
lo |= l << i;
|
||
|
hi |= h << i;
|
||
|
if (i)
|
||
|
hi |= l >> (32-i);
|
||
|
i += len0*8 - 1;
|
||
|
|
||
|
while (i >= 8)
|
||
|
{
|
||
|
*dest++ = lo;
|
||
|
lo = (lo >> 8U) | (hi << 24);
|
||
|
hi >>= 8;
|
||
|
i -= 8;
|
||
|
}
|
||
|
}
|
||
|
while (len0 == 5);
|
||
|
return dest-start;
|
||
|
}
|