diff --git a/CHANGES b/CHANGES index 71ba546..6a983c4 100644 --- a/CHANGES +++ b/CHANGES @@ -9,6 +9,7 @@ add el-cheapo MIME decoding to test/uudecode make install forgot to install ndelay.h fix typos in several man pages (Hynek Schlawack) + add stralloc versions of textcode API (Kai Ruemmler) 0.14: avoid bus errors in byte_copy diff --git a/textcode.h b/textcode.h index 1e66bfe..1fb6ad2 100644 --- a/textcode.h +++ b/textcode.h @@ -20,6 +20,30 @@ unsigned int scan_urlencoded(const char *src,char *dest,unsigned int *destlen); unsigned int scan_yenc(const char *src,char *dest,unsigned int *destlen); unsigned int scan_hexdump(const char *src,char *dest,unsigned int *destlen); +#ifdef STRALLOC_H +/* These take len bytes from src and write them in encoded form to sa. + * As the stralloc_* functions do, 1 + * is returned. If they run out of memory, sa contains the bytes already + * written and 0 is returned. */ +int fmt_quotedprintable_sa(stralloc *sa,const char* src,unsigned int len); +int fmt_base64_sa(stralloc *sa,const char* src,unsigned int len); +int fmt_uuencoded_sa(stralloc *sa,const char* src,unsigned int len); +int fmt_urlencoded_sa(stralloc *sa,const char* src,unsigned int len); +int fmt_yenc_sa(stralloc *sa,const char* src,unsigned int len); +int fmt_hexdump_sa(stralloc *sa,const char* src,unsigned int len); + +/* These read one line from src, decoded it, and write the result to + * sa. As the stralloc_* functions do, 1 + * is returned. If they run out of memory, sa contains the bytes already + * written and 0 is returned. */ +int scan_base64_sa(const char *src,stralloc* sa); +int scan_quotedprintable_sa(const char *src,stralloc* sa); +int scan_uuencoded_sa(const char *src,stralloc *sa); +int scan_urlencoded_sa(const char *src,stralloc *sa); +int scan_yenc_sa(const char *src,stralloc *sa); +int scan_hexdump_sa(const char *src,stralloc *sa); +#endif + extern const char base64[64]; #endif diff --git a/textcode/fmt_base64_sa.c b/textcode/fmt_base64_sa.c new file mode 100644 index 0000000..9ef7743 --- /dev/null +++ b/textcode/fmt_base64_sa.c @@ -0,0 +1,28 @@ +#include "fmt.h" +#include "stralloc.h" +#include "textcode.h" +#include "haveinline.h" + +int fmt_base64_sa(stralloc *sa,const char* src,unsigned int len) { + register const unsigned char* s=(const unsigned char*) src; + unsigned short bits=0,temp=0; + unsigned long i; + char dest; + for (i=0; i6) { + dest=base64[((temp>>(bits-6))&63)]; + if (!stralloc_catb(sa, &dest, 1)) return 0; + bits-=6; + } + } + if (bits) { + temp<<=(6-bits); + dest=base64[temp&63]; + if (!stralloc_catb(sa, &dest, 1)) return 0; + } + while (sa->len&3) { + if (!stralloc_catb(sa, "=", 1)) return 0; + } + return 1; +} diff --git a/textcode/fmt_hexdump_sa.c b/textcode/fmt_hexdump_sa.c new file mode 100644 index 0000000..7499311 --- /dev/null +++ b/textcode/fmt_hexdump_sa.c @@ -0,0 +1,21 @@ +#include "fmt.h" +#include "stralloc.h" +#include "textcode.h" +#include "str.h" +#include "haveinline.h" + +static inline int tohex(char c) { + return c>9?c-10+'a':c+'0'; +} + +int fmt_hexdump_sa(stralloc* sa,const char* src,unsigned int len) { + register const unsigned char* s=(const unsigned char*) src; + unsigned long i; + for (i=0; i>4); + dest[1]=tohex(s[i]&15); + if (!stralloc_catb(sa, dest, 2)) return 0; + } + return 1; +} diff --git a/textcode/fmt_quotedprintable_sa.c b/textcode/fmt_quotedprintable_sa.c new file mode 100644 index 0000000..09f0a28 --- /dev/null +++ b/textcode/fmt_quotedprintable_sa.c @@ -0,0 +1,25 @@ +#include "fmt.h" +#include "stralloc.h" +#include "textcode.h" +#include "haveinline.h" + +static inline int tohex(char c) { + return c>9?c-10+'A':c+'0'; +} + +int fmt_quotedprintable_sa(stralloc* sa,const char* src,unsigned int len) { + register const unsigned char* s=(const unsigned char*) src; + unsigned long i; + for (i=0; i>4); + dest[2]=tohex(s[i]&15); + if (!stralloc_catb(sa, dest, 3)) return 0; + } else { + if (!stralloc_catb(sa, s + i, 1)) return 0; + } + } + return 1; +} diff --git a/textcode/fmt_urlencoded_sa.c b/textcode/fmt_urlencoded_sa.c new file mode 100644 index 0000000..bcd01b9 --- /dev/null +++ b/textcode/fmt_urlencoded_sa.c @@ -0,0 +1,26 @@ +#include "fmt.h" +#include "stralloc.h" +#include "textcode.h" +#include "str.h" +#include "haveinline.h" + +static inline int tohex(char c) { + return c>9?c-10+'A':c+'0'; +} + +int fmt_urlencoded_sa(stralloc *sa,const char* src,unsigned int len) { + const char unsafe[]=" %<>\"#{}|\\^~[]`;/?:@=&"; + register const unsigned char* s=(const unsigned char*) src; + unsigned long i; + for (i=0; i>4); + dest[2]=tohex(s[i]&15); + if (!stralloc_catb(sa, &dest, 3)) return 0; + } else { + if (!stralloc_catb(sa, s+i, 1)) return 0; + } + } + return 1; +} diff --git a/textcode/fmt_uuencoded_sa.c b/textcode/fmt_uuencoded_sa.c new file mode 100644 index 0000000..c0be7b6 --- /dev/null +++ b/textcode/fmt_uuencoded_sa.c @@ -0,0 +1,38 @@ +#include "fmt.h" +#include "stralloc.h" +#include "textcode.h" +#include "haveinline.h" + +static inline unsigned int enc(unsigned char x) { + return ((x-1)&077)+'!'; +} + +int fmt_uuencoded_sa(stralloc* sa,const char* src,unsigned int len) { + unsigned int i; + register const unsigned char* s=(const unsigned char*) src; + unsigned long tmp; + while (len) { + { + register unsigned int diff; + char c; + if (len>45) { i=15; diff=45; } else { i=(len+2)/3; diff=len; } + c=enc(diff); + len-=diff; + if (!stralloc_catb(sa,&c,1)) return 0; + } + for (; i; --i) { + char dest[4]; + tmp=((unsigned long)s[0] << 16) + + ((unsigned long)s[1] << 8) + + ((unsigned long)s[2]); + dest[0]=enc((tmp>>(3*6))&077); + dest[1]=enc((tmp>>(2*6))&077); + dest[2]=enc((tmp>>(1*6))&077); + dest[3]=enc(tmp&077); + s+=3; + if (!stralloc_catb(sa,&dest,4)) return 0; + } + if (!stralloc_catb(sa,"\n",1)) return 0; + } + return 1; +} diff --git a/textcode/fmt_yenc_sa.c b/textcode/fmt_yenc_sa.c new file mode 100644 index 0000000..910db8c --- /dev/null +++ b/textcode/fmt_yenc_sa.c @@ -0,0 +1,45 @@ +#include "fmt.h" +#include "stralloc.h" +#include "textcode.h" + +int fmt_yenc_sa(stralloc *sa,const char* src,unsigned int len) { + register const unsigned char* s=(const unsigned char*) src; + unsigned long i; + int linelen=0; + for (i=0; i='a' && x<='z') return x-'a'+26; + if (x>='0' && x<='9') return x-'0'+26+26; + switch (x) { + case '+': return 62; + case '/': return 63; + default: return -1; + } +} + +int scan_base64_sa(const char *src,stralloc* sa) { + unsigned short tmp=0,bits=0; + register const unsigned char* s=(const unsigned char*) src; + for (;;) { + int a=dec(*s); + if (a<0) { + while (*s=='=') ++s; + break; + } + tmp=(tmp<<6)|a; bits+=6; + ++s; + if (bits>=8) { + char dest=(tmp>>(bits-=8)); + if (!stralloc_catb(sa,&dest,1)) return 0; + } + } + return 1; +} diff --git a/textcode/scan_hexdump.c b/textcode/scan_hexdump.c index 828a775..7a82de1 100644 --- a/textcode/scan_hexdump.c +++ b/textcode/scan_hexdump.c @@ -19,7 +19,7 @@ unsigned int scan_hexdump(const char *src,char *dest,unsigned int *destlen) { j=fromhex(s[i+1]); if (j<0) break; dest[written]|=j; - i+=2; + ++i; ++written; } *destlen=written; diff --git a/textcode/scan_hexdump_sa.c b/textcode/scan_hexdump_sa.c new file mode 100644 index 0000000..7ae5bc6 --- /dev/null +++ b/textcode/scan_hexdump_sa.c @@ -0,0 +1,28 @@ +#include "fmt.h" +#include "stralloc.h" +#include "textcode.h" +#include "haveinline.h" + +static inline int fromhex(char c) { + if (c>='0' && c<='9') return c-'0'; + if (c>='A' && c<='F') return c-'A'+10; + if (c>='a' && c<='f') return c-'a'+10; + return -1; +} + +int scan_hexdump_sa(const char *src,stralloc *sa) { + register const unsigned char* s=(const unsigned char*) src; + unsigned long i; + for (i=0; s[i]; ++i) { + char dest; + int j=fromhex(s[i]); + if (j<0) break; + dest=j<<4; + j=fromhex(s[i+1]); + if (j<0) break; + dest|=j; + ++i; + if (!stralloc_catb(sa, &dest, 1)) return 0; + } + return 1; +} diff --git a/textcode/scan_quotedprintable_sa.c b/textcode/scan_quotedprintable_sa.c new file mode 100644 index 0000000..9782d09 --- /dev/null +++ b/textcode/scan_quotedprintable_sa.c @@ -0,0 +1,32 @@ +#include "fmt.h" +#include "stralloc.h" +#include "textcode.h" +#include "haveinline.h" + +static inline int fromhex(char c) { + if (c>='0' && c<='9') return c-'0'; + if (c>='A' && c<='F') return c-'A'+10; + if (c>='a' && c<='f') return c-'a'+10; + return -1; +} + +int scan_quotedprintable_sa(const char *src,stralloc* sa) { + register const unsigned char* s=(const unsigned char*) src; + unsigned long i; + for (i=0; s[i]; ++i) { + if (s[i]=='=') { + char dest; + int j=fromhex(s[i+1]); + if (j<0) break; + dest=j<<4; + j=fromhex(s[i+2]); + if (j<0) break; + dest|=j; + if (!stralloc_catb(sa, &dest, 1)) return 0; + i+=2; + } else { + if (!stralloc_catb(sa, s+i, 1)) return 0; + } + } + return 1; +} diff --git a/textcode/scan_urlencoded_sa.c b/textcode/scan_urlencoded_sa.c new file mode 100644 index 0000000..42805a1 --- /dev/null +++ b/textcode/scan_urlencoded_sa.c @@ -0,0 +1,33 @@ +#include "fmt.h" +#include "stralloc.h" +#include "textcode.h" +#include "haveinline.h" + +static inline int fromhex(char c) { + if (c>='0' && c<='9') return c-'0'; + if (c>='A' && c<='F') return c-'A'+10; + if (c>='a' && c<='f') return c-'a'+10; + return -1; +} + +int scan_urlencoded_sa(const char *src, stralloc *sa) { + register const unsigned char* s=(const unsigned char*) src; + unsigned long i; + for (i=0; s[i]; ++i) { + if (s[i]=='%') { + char dest; + int j=fromhex(s[i+1]); + if (j<0) break; + dest=j<<4; + j=fromhex(s[i+2]); + if (j<0) break; + dest|=j; + i+=2; + if (!stralloc_catb(sa, &dest, 1)) return 0; + } else if (s[i]=='+') { + if (!stralloc_catb(sa," ",1)) return 0; + } else + if (!stralloc_catb(sa,s+i,1)) return 0; + } + return 1; +} diff --git a/textcode/scan_uuencoded_sa.c b/textcode/scan_uuencoded_sa.c new file mode 100644 index 0000000..98202f4 --- /dev/null +++ b/textcode/scan_uuencoded_sa.c @@ -0,0 +1,25 @@ +#include "stralloc.h" +#include "textcode.h" + +int scan_uuencoded_sa(const char *src,stralloc *sa) { + unsigned int len; + unsigned long tmp; + register const unsigned char* s=(const unsigned char*) src; + if ((len=*s-' ')>64) return 0; len&=63; + ++s; + while (len>0) { + char dest[3]; + unsigned int l=len; + if (s[0]-' '>64 || s[1]-' '>64 || s[2]-' '>64 || s[3]-' '>64) return 0; + tmp=(((s[0]-' ')&077) << (3*6)) + + (((s[1]-' ')&077) << (2*6)) + + (((s[2]-' ')&077) << (1*6)) + + (((s[3]-' ')&077)); + s+=4; + if (len) { dest[0]=tmp>>16; --len; } + if (len) { dest[1]=tmp>>8; --len; } + if (len) { dest[2]=tmp&0xff; --len; } + if (!stralloc_catb(sa,dest,l-len)) return 0; + } + return 1; +} diff --git a/textcode/scan_yenc_sa.c b/textcode/scan_yenc_sa.c new file mode 100644 index 0000000..068c460 --- /dev/null +++ b/textcode/scan_yenc_sa.c @@ -0,0 +1,21 @@ +#include "fmt.h" +#include "stralloc.h" +#include "textcode.h" + +int scan_yenc_sa(const char *src,stralloc *sa) { + register const unsigned char* s=(const unsigned char*) src; + unsigned long i; + for (i=0; s[i]; ++i) { + char dest; + if (s[i]=='=') { + ++i; + if (s[i]=='y') break; + dest=s[i]-64-42; + } else if (s[i]=='\n' || s[i]=='\r' || s[i]=='\0') + break; + else + dest=s[i]-42; + if (!stralloc_catb(sa,&dest,1)) return 0; + } + return 1; +}