add man page for scan_base64, handle partial blocks better

master
leitner 8 years ago
parent 23b1412d47
commit 959151a24d

@ -0,0 +1,34 @@
.TH scan_base64 3
.SH NAME
scan_base64 \- decode base64 encoded data
.SH SYNTAX
.B #include <textcode.h>
size_t \fBscan_base64\fP(const char *\fIsrc\fR,char *\fIdest\fR,size_t* \fIdestlen\fR);
.SH DESCRIPTION
scan_base64 decodes base64 encoded data from src into dest.
It will stop when it encountes any non-valid input characters.
It will then write the number of decoded bytes in dest into *destlen,
and return the number of bytes decoded from src.
Note that real world base64 encoded data is sometimes permitted to
contain whitespace characters or new lines. This function will not allow
those and return the decoded data until then.
base64 works by taking 3 bytes of binary input and converting them into
4 bytes of printable ASCII. If the input ends in the middle of a base64
4-byte-tuple, scan_base64 will disregard it.
Many base64 variants demand padding in the last block. Some don't. This
implementation will consume padding if it is there, but will not
complain if it is not.
.SH "RETURN VALUE"
scan_base64 returns the number of bytes successfully scanned and
processed from src.
.SH EXAMPLES
scan_base64("Zm5vcmQ=",buf,&i) -> return 8, i=5, buf="fnord"
.SH "SEE ALSO"
scan_xlong(3), scan_8long(3), fmt_ulong(3)

@ -15,20 +15,39 @@ static inline int dec(unsigned char x) {
size_t scan_base64(const char *src,char *dest,size_t *destlen) { size_t scan_base64(const char *src,char *dest,size_t *destlen) {
unsigned short tmp=0,bits=0; unsigned short tmp=0,bits=0;
register const unsigned char* s=(const unsigned char*) src; register const unsigned char* s=(const unsigned char*) src;
const char* orig=dest; const char* orig=src;
for (;;) { size_t i,j=0;
for (i=0;;) {
int a=dec(*s); int a=dec(*s);
if (a<0) { if (a<0) {
int equal=(*s=='=');
while (*s=='=' && ((s-(const unsigned char*)src)&3)) ++s; while (*s=='=' && ((s-(const unsigned char*)src)&3)) ++s;
tmp &= ((1<<bits)-1);
if (!tmp || equal) { j=i; orig=s; }
break; break;
} }
tmp=(tmp<<6)|a; bits+=6; tmp=(tmp<<6)|a; bits+=6;
++s; ++s;
if (bits>=8) { if (bits>=8) {
*dest=(tmp>>(bits-=8)); bits-=8;
++dest; if (dest) dest[i]=(tmp>>bits);
++i;
if (!bits) { j=i; orig=s; }
} }
} }
*destlen=dest-orig; if (destlen) *destlen=j;
return (const char*)s-src; return orig-src;
} }
#ifdef UNITTEST
#include <assert.h>
#include <string.h>
#include <stdio.h>
int main() {
char buf[100];
size_t i,l;
memset(buf,0,10); assert(scan_base64("Zm5vcmQ=",buf,&l)==8 && l==5 && !memcmp(buf,"fnord",6));
memset(buf,0,10); assert(scan_base64("Zm5vcmQ",buf,&l)==7 && l==5 && !memcmp(buf,"fnord",6));
}
#endif

Loading…
Cancel
Save