Message ID | ce09322623e5f1feb82feb6c09fe1786a594223b.1274516288.git.jan.kiszka@web.de |
---|---|
State | New |
Headers | show |
On Sat, May 22, 2010 at 8:18 AM, Jan Kiszka <jan.kiszka@web.de> wrote: > From: Jan Kiszka <jan.kiszka@siemens.com> > > Will be used by QBuffer. > > Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> > --- > Makefile.objs | 2 +- > base64.c | 202 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > base64.h | 18 +++++ > 3 files changed, 221 insertions(+), 1 deletions(-) > create mode 100644 base64.c > create mode 100644 base64.h > > diff --git a/Makefile.objs b/Makefile.objs > index acbaf22..2c603b2 100644 > --- a/Makefile.objs > +++ b/Makefile.objs > @@ -2,7 +2,7 @@ > # QObject > qobject-obj-y = qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o > qobject-obj-y += qjson.o json-lexer.o json-streamer.o json-parser.o > -qobject-obj-y += qerror.o > +qobject-obj-y += qerror.o base64.o > > ####################################################################### > # block-obj-y is code used by both qemu system emulation and qemu-img > diff --git a/base64.c b/base64.c > new file mode 100644 > index 0000000..543e8c6 > --- /dev/null > +++ b/base64.c > @@ -0,0 +1,202 @@ > +/* > + * Base64 encoder/decoder conforming to RFC 4648 > + * (based on Mozilla's nsprpub/lib/libc/src/base64.c) > + * > + * Copyright (C) 2010 Siemens AG > + * > + * Authors: > + * Jan Kiszka <jan.kiszka@siemens.com> > + * > + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. > + * See the COPYING.LIB file in the top-level directory. > + * > + */ > + > +#include "inttypes.h" Why not <inttypes.h>? > +#include "base64.h" > + > +static const char base[] = > + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; > + > +static void encode3to4(const char *src, char *dest) > +{ > + uint32_t b32 = 0; > + int i, j = 18; > + > + for (i = 0; i < 3; i++) { > + b32 <<= 8; > + b32 |= src[i]; > + } > + for (i = 0; i < 4; i++) { > + dest[i] = base[(b32 >> j) & 0x3F]; > + j -= 6; > + } > +} > + > +static void encode2to4(const char *src, char *dest) > +{ > + dest[0] = base[(src[0] >> 2) & 0x3F]; > + dest[1] = base[((src[0] & 0x03) << 4) | ((src[1] >> 4) & 0x0F)]; > + dest[2] = base[(src[1] & 0x0F) << 2]; > + dest[3] = '='; > +} > + > +static void encode1to4(const char *src, char *dest) > +{ > + dest[0] = base[(src[0] >> 2) & 0x3F]; > + dest[1] = base[(src[0] & 0x03) << 4]; > + dest[2] = '='; > + dest[3] = '='; > +} > + > +/* > + * Encode data in 'src' of length 'srclen' to a base64 string, saving the > + * null-terminated result in 'dest'. The size of the destition buffer must be > + * at least ((srclen + 2) / 3) * 4 + 1. > + */ > +void base64_encode(const void *src, size_t srclen, char *dest) > +{ > + while (srclen >= 3) { > + encode3to4(src, dest); > + src += 3; > + dest += 4; > + srclen -= 3; > + } > + switch (srclen) { > + case 2: > + encode2to4(src, dest); > + dest += 4; > + break; > + case 1: > + encode1to4(src, dest); > + dest += 4; > + break; > + case 0: > + break; > + } > + dest[0] = 0; > +} > + > +static int32_t codetovalue(char c) > +{ > + if (c >= 'A' && c <= 'Z') { > + return c - 'A'; > + } else if (c >= 'a' && c <= 'z') { > + return c - 'a' + 26; > + } else if (c >= '0' && c <= '9') { > + return c - '0' + 52; > + } else if (c == '+') { > + return 62; > + } else if ( c == '/') { > + return 63; > + } else { > + return -1; > + } > +} > + > +static int decode4to3 (const char *src, char *dest) > +{ > + uint32_t b32 = 0; > + int32_t bits; > + int i; > + > + for (i = 0; i < 4; i++) { > + bits = codetovalue(src[i]); > + if (bits < 0) { > + return bits; > + } > + b32 <<= 6; > + b32 |= bits; > + } > + dest[0] = (b32 >> 16) & 0xFF; > + dest[1] = (b32 >> 8) & 0xFF; > + dest[2] = b32 & 0xFF; > + > + return 0; > +} > + > +static int decode3to2(const char *src, char *dest) > +{ > + uint32_t b32 = 0; > + int32_t bits; > + > + bits = codetovalue(src[0]); > + if (bits < 0) { > + return bits; > + } > + b32 = (uint32_t)bits; > + b32 <<= 6; > + > + bits = codetovalue(src[1]); > + if (bits < 0) { > + return bits; > + } > + b32 |= (uint32_t)bits; > + b32 <<= 4; > + > + bits = codetovalue(src[2]); > + if (bits < 0) { > + return bits; > + } > + b32 |= ((uint32_t)bits) >> 2; > + > + dest[0] = (b32 >> 8) & 0xFF; > + dest[1] = b32 & 0xFF; > + > + return 0; > +} > + > +static int decode2to1(const char *src, char *dest) > +{ > + uint32_t b32; > + int32_t bits; > + > + bits = codetovalue(src[0]); > + if (bits < 0) { > + return bits; > + } > + b32 = (uint32_t)bits << 2; > + > + bits = codetovalue(src[1]); > + if (bits < 0) { > + return bits; > + } > + b32 |= ((uint32_t)bits) >> 4; > + > + dest[0] = b32; > + > + return 0; > +} > + > +/* > + * Convert string 'src' of length 'srclen' from base64 to binary form, > + * saving the result in 'dest'. The size of the destination buffer must be at > + * least srclen * 3 / 4. > + * > + * Returns 0 on success, -1 on conversion error. > + */ > +int base64_decode(const char *src, size_t srclen, void *dest) I think dest should be char *, like all the functions where dest is passed to. > +{ > + int ret; > + > + while (srclen >= 4) { > + ret = decode4to3(src, dest); > + if (ret < 0) { > + return ret; > + } > + src += 4; > + dest += 3; > + srclen -= 4; > + } > + > + switch (srclen) { > + case 3: > + return decode3to2(src, dest); > + case 2: > + return decode2to1(src, dest); > + case 1: > + return -1; > + default: /* 0 */ > + return 0; > + } > +} > diff --git a/base64.h b/base64.h > new file mode 100644 > index 0000000..9a0e03a > --- /dev/null > +++ b/base64.h > @@ -0,0 +1,18 @@ > +/* > + * Base64 encoder/decoder conforming to RFC 4648 > + * (based on Mozilla's nsprpub/lib/libc/src/base64.c) > + * > + * Copyright (C) 2010 Siemens AG > + * > + * Authors: > + * Jan Kiszka <jan.kiszka@siemens.com> > + * > + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. > + * See the COPYING.LIB file in the top-level directory. > + * > + */ > + > +#include <unistd.h> Maybe <stddef.h> instead, it's only for size_t? > + > +void base64_encode(const void *src, size_t srclen, char *dest); > +int base64_decode(const char *src, size_t srclen, void *dest); > -- > 1.6.0.2 > > >
Blue Swirl wrote: > On Sat, May 22, 2010 at 8:18 AM, Jan Kiszka <jan.kiszka@web.de> wrote: >> From: Jan Kiszka <jan.kiszka@siemens.com> >> >> Will be used by QBuffer. >> >> Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> >> --- >> Makefile.objs | 2 +- >> base64.c | 202 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ >> base64.h | 18 +++++ >> 3 files changed, 221 insertions(+), 1 deletions(-) >> create mode 100644 base64.c >> create mode 100644 base64.h >> >> diff --git a/Makefile.objs b/Makefile.objs >> index acbaf22..2c603b2 100644 >> --- a/Makefile.objs >> +++ b/Makefile.objs >> @@ -2,7 +2,7 @@ >> # QObject >> qobject-obj-y = qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o >> qobject-obj-y += qjson.o json-lexer.o json-streamer.o json-parser.o >> -qobject-obj-y += qerror.o >> +qobject-obj-y += qerror.o base64.o >> >> ####################################################################### >> # block-obj-y is code used by both qemu system emulation and qemu-img >> diff --git a/base64.c b/base64.c >> new file mode 100644 >> index 0000000..543e8c6 >> --- /dev/null >> +++ b/base64.c >> @@ -0,0 +1,202 @@ >> +/* >> + * Base64 encoder/decoder conforming to RFC 4648 >> + * (based on Mozilla's nsprpub/lib/libc/src/base64.c) >> + * >> + * Copyright (C) 2010 Siemens AG >> + * >> + * Authors: >> + * Jan Kiszka <jan.kiszka@siemens.com> >> + * >> + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. >> + * See the COPYING.LIB file in the top-level directory. >> + * >> + */ >> + >> +#include "inttypes.h" > > Why not <inttypes.h>? Oops, no intention. > >> +#include "base64.h" >> + >> +static const char base[] = >> + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; >> + >> +static void encode3to4(const char *src, char *dest) >> +{ >> + uint32_t b32 = 0; >> + int i, j = 18; >> + >> + for (i = 0; i < 3; i++) { >> + b32 <<= 8; >> + b32 |= src[i]; >> + } >> + for (i = 0; i < 4; i++) { >> + dest[i] = base[(b32 >> j) & 0x3F]; >> + j -= 6; >> + } >> +} >> + >> +static void encode2to4(const char *src, char *dest) >> +{ >> + dest[0] = base[(src[0] >> 2) & 0x3F]; >> + dest[1] = base[((src[0] & 0x03) << 4) | ((src[1] >> 4) & 0x0F)]; >> + dest[2] = base[(src[1] & 0x0F) << 2]; >> + dest[3] = '='; >> +} >> + >> +static void encode1to4(const char *src, char *dest) >> +{ >> + dest[0] = base[(src[0] >> 2) & 0x3F]; >> + dest[1] = base[(src[0] & 0x03) << 4]; >> + dest[2] = '='; >> + dest[3] = '='; >> +} >> + >> +/* >> + * Encode data in 'src' of length 'srclen' to a base64 string, saving the >> + * null-terminated result in 'dest'. The size of the destition buffer must be >> + * at least ((srclen + 2) / 3) * 4 + 1. >> + */ >> +void base64_encode(const void *src, size_t srclen, char *dest) >> +{ >> + while (srclen >= 3) { >> + encode3to4(src, dest); >> + src += 3; >> + dest += 4; >> + srclen -= 3; >> + } >> + switch (srclen) { >> + case 2: >> + encode2to4(src, dest); >> + dest += 4; >> + break; >> + case 1: >> + encode1to4(src, dest); >> + dest += 4; >> + break; >> + case 0: >> + break; >> + } >> + dest[0] = 0; >> +} >> + >> +static int32_t codetovalue(char c) >> +{ >> + if (c >= 'A' && c <= 'Z') { >> + return c - 'A'; >> + } else if (c >= 'a' && c <= 'z') { >> + return c - 'a' + 26; >> + } else if (c >= '0' && c <= '9') { >> + return c - '0' + 52; >> + } else if (c == '+') { >> + return 62; >> + } else if ( c == '/') { >> + return 63; >> + } else { >> + return -1; >> + } >> +} >> + >> +static int decode4to3 (const char *src, char *dest) >> +{ >> + uint32_t b32 = 0; >> + int32_t bits; >> + int i; >> + >> + for (i = 0; i < 4; i++) { >> + bits = codetovalue(src[i]); >> + if (bits < 0) { >> + return bits; >> + } >> + b32 <<= 6; >> + b32 |= bits; >> + } >> + dest[0] = (b32 >> 16) & 0xFF; >> + dest[1] = (b32 >> 8) & 0xFF; >> + dest[2] = b32 & 0xFF; >> + >> + return 0; >> +} >> + >> +static int decode3to2(const char *src, char *dest) >> +{ >> + uint32_t b32 = 0; >> + int32_t bits; >> + >> + bits = codetovalue(src[0]); >> + if (bits < 0) { >> + return bits; >> + } >> + b32 = (uint32_t)bits; >> + b32 <<= 6; >> + >> + bits = codetovalue(src[1]); >> + if (bits < 0) { >> + return bits; >> + } >> + b32 |= (uint32_t)bits; >> + b32 <<= 4; >> + >> + bits = codetovalue(src[2]); >> + if (bits < 0) { >> + return bits; >> + } >> + b32 |= ((uint32_t)bits) >> 2; >> + >> + dest[0] = (b32 >> 8) & 0xFF; >> + dest[1] = b32 & 0xFF; >> + >> + return 0; >> +} >> + >> +static int decode2to1(const char *src, char *dest) >> +{ >> + uint32_t b32; >> + int32_t bits; >> + >> + bits = codetovalue(src[0]); >> + if (bits < 0) { >> + return bits; >> + } >> + b32 = (uint32_t)bits << 2; >> + >> + bits = codetovalue(src[1]); >> + if (bits < 0) { >> + return bits; >> + } >> + b32 |= ((uint32_t)bits) >> 4; >> + >> + dest[0] = b32; >> + >> + return 0; >> +} >> + >> +/* >> + * Convert string 'src' of length 'srclen' from base64 to binary form, >> + * saving the result in 'dest'. The size of the destination buffer must be at >> + * least srclen * 3 / 4. >> + * >> + * Returns 0 on success, -1 on conversion error. >> + */ >> +int base64_decode(const char *src, size_t srclen, void *dest) > > I think dest should be char *, like all the functions where dest is passed to. The output may but need not be a string, it's binary data. And to avoid needless warnings about signedness mismatches if unsigned char or uint8_t buffers are passed, I chose void *. > >> +{ >> + int ret; >> + >> + while (srclen >= 4) { >> + ret = decode4to3(src, dest); >> + if (ret < 0) { >> + return ret; >> + } >> + src += 4; >> + dest += 3; >> + srclen -= 4; >> + } >> + >> + switch (srclen) { >> + case 3: >> + return decode3to2(src, dest); >> + case 2: >> + return decode2to1(src, dest); >> + case 1: >> + return -1; >> + default: /* 0 */ >> + return 0; >> + } >> +} >> diff --git a/base64.h b/base64.h >> new file mode 100644 >> index 0000000..9a0e03a >> --- /dev/null >> +++ b/base64.h >> @@ -0,0 +1,18 @@ >> +/* >> + * Base64 encoder/decoder conforming to RFC 4648 >> + * (based on Mozilla's nsprpub/lib/libc/src/base64.c) >> + * >> + * Copyright (C) 2010 Siemens AG >> + * >> + * Authors: >> + * Jan Kiszka <jan.kiszka@siemens.com> >> + * >> + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. >> + * See the COPYING.LIB file in the top-level directory. >> + * >> + */ >> + >> +#include <unistd.h> > > Maybe <stddef.h> instead, it's only for size_t? Makes sense. > >> + >> +void base64_encode(const void *src, size_t srclen, char *dest); >> +int base64_decode(const char *src, size_t srclen, void *dest); >> -- >> 1.6.0.2 >> >> >> Thanks, Jan
On 05/23/2010 10:55 AM, Jan Kiszka wrote: >>> +/* >>> + * Convert string 'src' of length 'srclen' from base64 to binary form, >>> + * saving the result in 'dest'. The size of the destination buffer must be at >>> + * least srclen * 3 / 4. >>> + * >>> + * Returns 0 on success, -1 on conversion error. >>> + */ >>> +int base64_decode(const char *src, size_t srclen, void *dest) >>> >> I think dest should be char *, like all the functions where dest is passed to. >> > The output may but need not be a string, it's binary data. And to avoid > needless warnings about signedness mismatches if unsigned char or > uint8_t buffers are passed, I chose void *. > I think qemu is pretty consistent in using uint8_t for binary, and void * is a little dangerous as it allows passing any kind of data (anything above a byte is subject to endianness issues for example). But I don't feel strongly about this.
Avi Kivity wrote: > On 05/23/2010 10:55 AM, Jan Kiszka wrote: >>>> +/* >>>> + * Convert string 'src' of length 'srclen' from base64 to binary form, >>>> + * saving the result in 'dest'. The size of the destination buffer >>>> must be at >>>> + * least srclen * 3 / 4. >>>> + * >>>> + * Returns 0 on success, -1 on conversion error. >>>> + */ >>>> +int base64_decode(const char *src, size_t srclen, void *dest) >>>> >>> I think dest should be char *, like all the functions where dest is >>> passed to. >>> >> The output may but need not be a string, it's binary data. And to avoid >> needless warnings about signedness mismatches if unsigned char or >> uint8_t buffers are passed, I chose void *. >> > > I think qemu is pretty consistent in using uint8_t for binary, and void > * is a little dangerous as it allows passing any kind of data (anything > above a byte is subject to endianness issues for example). > > But I don't feel strongly about this. > Let's go for consistency: I switched to uint8_t for the binary input/output. Jan
diff --git a/Makefile.objs b/Makefile.objs index acbaf22..2c603b2 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -2,7 +2,7 @@ # QObject qobject-obj-y = qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o qobject-obj-y += qjson.o json-lexer.o json-streamer.o json-parser.o -qobject-obj-y += qerror.o +qobject-obj-y += qerror.o base64.o ####################################################################### # block-obj-y is code used by both qemu system emulation and qemu-img diff --git a/base64.c b/base64.c new file mode 100644 index 0000000..543e8c6 --- /dev/null +++ b/base64.c @@ -0,0 +1,202 @@ +/* + * Base64 encoder/decoder conforming to RFC 4648 + * (based on Mozilla's nsprpub/lib/libc/src/base64.c) + * + * Copyright (C) 2010 Siemens AG + * + * Authors: + * Jan Kiszka <jan.kiszka@siemens.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#include "inttypes.h" +#include "base64.h" + +static const char base[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static void encode3to4(const char *src, char *dest) +{ + uint32_t b32 = 0; + int i, j = 18; + + for (i = 0; i < 3; i++) { + b32 <<= 8; + b32 |= src[i]; + } + for (i = 0; i < 4; i++) { + dest[i] = base[(b32 >> j) & 0x3F]; + j -= 6; + } +} + +static void encode2to4(const char *src, char *dest) +{ + dest[0] = base[(src[0] >> 2) & 0x3F]; + dest[1] = base[((src[0] & 0x03) << 4) | ((src[1] >> 4) & 0x0F)]; + dest[2] = base[(src[1] & 0x0F) << 2]; + dest[3] = '='; +} + +static void encode1to4(const char *src, char *dest) +{ + dest[0] = base[(src[0] >> 2) & 0x3F]; + dest[1] = base[(src[0] & 0x03) << 4]; + dest[2] = '='; + dest[3] = '='; +} + +/* + * Encode data in 'src' of length 'srclen' to a base64 string, saving the + * null-terminated result in 'dest'. The size of the destition buffer must be + * at least ((srclen + 2) / 3) * 4 + 1. + */ +void base64_encode(const void *src, size_t srclen, char *dest) +{ + while (srclen >= 3) { + encode3to4(src, dest); + src += 3; + dest += 4; + srclen -= 3; + } + switch (srclen) { + case 2: + encode2to4(src, dest); + dest += 4; + break; + case 1: + encode1to4(src, dest); + dest += 4; + break; + case 0: + break; + } + dest[0] = 0; +} + +static int32_t codetovalue(char c) +{ + if (c >= 'A' && c <= 'Z') { + return c - 'A'; + } else if (c >= 'a' && c <= 'z') { + return c - 'a' + 26; + } else if (c >= '0' && c <= '9') { + return c - '0' + 52; + } else if (c == '+') { + return 62; + } else if ( c == '/') { + return 63; + } else { + return -1; + } +} + +static int decode4to3 (const char *src, char *dest) +{ + uint32_t b32 = 0; + int32_t bits; + int i; + + for (i = 0; i < 4; i++) { + bits = codetovalue(src[i]); + if (bits < 0) { + return bits; + } + b32 <<= 6; + b32 |= bits; + } + dest[0] = (b32 >> 16) & 0xFF; + dest[1] = (b32 >> 8) & 0xFF; + dest[2] = b32 & 0xFF; + + return 0; +} + +static int decode3to2(const char *src, char *dest) +{ + uint32_t b32 = 0; + int32_t bits; + + bits = codetovalue(src[0]); + if (bits < 0) { + return bits; + } + b32 = (uint32_t)bits; + b32 <<= 6; + + bits = codetovalue(src[1]); + if (bits < 0) { + return bits; + } + b32 |= (uint32_t)bits; + b32 <<= 4; + + bits = codetovalue(src[2]); + if (bits < 0) { + return bits; + } + b32 |= ((uint32_t)bits) >> 2; + + dest[0] = (b32 >> 8) & 0xFF; + dest[1] = b32 & 0xFF; + + return 0; +} + +static int decode2to1(const char *src, char *dest) +{ + uint32_t b32; + int32_t bits; + + bits = codetovalue(src[0]); + if (bits < 0) { + return bits; + } + b32 = (uint32_t)bits << 2; + + bits = codetovalue(src[1]); + if (bits < 0) { + return bits; + } + b32 |= ((uint32_t)bits) >> 4; + + dest[0] = b32; + + return 0; +} + +/* + * Convert string 'src' of length 'srclen' from base64 to binary form, + * saving the result in 'dest'. The size of the destination buffer must be at + * least srclen * 3 / 4. + * + * Returns 0 on success, -1 on conversion error. + */ +int base64_decode(const char *src, size_t srclen, void *dest) +{ + int ret; + + while (srclen >= 4) { + ret = decode4to3(src, dest); + if (ret < 0) { + return ret; + } + src += 4; + dest += 3; + srclen -= 4; + } + + switch (srclen) { + case 3: + return decode3to2(src, dest); + case 2: + return decode2to1(src, dest); + case 1: + return -1; + default: /* 0 */ + return 0; + } +} diff --git a/base64.h b/base64.h new file mode 100644 index 0000000..9a0e03a --- /dev/null +++ b/base64.h @@ -0,0 +1,18 @@ +/* + * Base64 encoder/decoder conforming to RFC 4648 + * (based on Mozilla's nsprpub/lib/libc/src/base64.c) + * + * Copyright (C) 2010 Siemens AG + * + * Authors: + * Jan Kiszka <jan.kiszka@siemens.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + * + */ + +#include <unistd.h> + +void base64_encode(const void *src, size_t srclen, char *dest); +int base64_decode(const char *src, size_t srclen, void *dest);