diff --git a/scan.h b/scan.h index 1fd7e73..78b1853 100644 --- a/scan.h +++ b/scan.h @@ -17,21 +17,45 @@ extern "C" { #define __pure__ #endif -/* interpret src as ASCII decimal number, write number to dest and - * return the number of bytes that were parsed */ +/* This file declared functions used to decode / scan / unmarshal + * integer or string values from a buffer. + * The first argument is always the source buffer, the second argument + * is a pointer to the destination (where to store the result). The + * return value is number of bytes scanned successfully. */ + +/* Interpret src as ASCII decimal number, write number to dest and + * return the number of bytes that were parsed. + * scan_ulong("23",&i) -> i=23, return 2 + * NB: leading + or - or space not accepted: + * scan_ulong("+23",&i) -> return 0 + * scan_ulong("-23",&i) -> return 0 + * scan_ulong(" 23",&i) -> return 0 + * scan_ulong("23,42",&i) -> i=23, return 2 + * NB: 023 for octal or 0x23 for hex are not supported! + * scan_ulong("0x23",&i) -> i=0, return 1 + * NB: will detect integer overflow and abort on excessively large + * values, i.e. on a 32-bit system: + * scan_ulong("4294967296",&i" -> i=429496729, return 9 */ size_t scan_ulong(const char *src,unsigned long *dest); +size_t scan_ulongn(const char* src,size_t n,unsigned long* dest); -/* interpret src as ASCII hexadecimal number, write number to dest and - * return the number of bytes that were parsed */ +/* Interpret src as ASCII hexadecimal number, write number to dest and + * return the number of bytes that were parsed. + * Note: leading '+' or '-' not accepted! */ size_t scan_xlong(const char *src,unsigned long *dest); +size_t scan_xlongn(const char *src,size_t n,unsigned long *dest); /* interpret src as ASCII octal number, write number to dest and - * return the number of bytes that were parsed */ + * return the number of bytes that were parsed. + * Note: leading '+' or '-' not accepted! */ size_t scan_8long(const char *src,unsigned long *dest); +size_t scan_8longn(const char *src,size_t n,unsigned long *dest); /* interpret src as signed ASCII decimal number, write number to dest - * and return the number of bytes that were parsed */ + * and return the number of bytes that were parsed. + * Note: leading spaces not accepted! */ size_t scan_long(const char *src,signed long *dest); +size_t scan_longn(const char *src,size_t n,signed long *dest); size_t scan_longlong(const char *src,signed long long *dest); size_t scan_ulonglong(const char *src,unsigned long long *dest); @@ -84,7 +108,17 @@ size_t scan_utf8(const char* in,size_t len,uint32_t* n) __pure__; size_t scan_asn1derlength(const char* in,size_t len,unsigned long long* n) __pure__; size_t scan_asn1dertag(const char* in,size_t len,unsigned long long* n) __pure__; -/* a few internal function that might be useful independently */ +/* parse a netstring, input buffer is in (len bytes). + * if parsing is successful: + * *dest points to string and *slen is size of string + * return number of bytes parsed + * else + * return 0 + * Note: *dest will point inside the input buffer! + */ +size_t scan_netstring(const char* in,size_t len,char** dest,size_t* slen) __pure__; + +/* internal function that might be useful independently */ /* convert from hex ASCII, return 0 to 15 for success or -1 for failure */ int scan_fromhex(unsigned char c); diff --git a/scan/scan_8longn.c b/scan/scan_8longn.c new file mode 100644 index 0000000..61885d6 --- /dev/null +++ b/scan/scan_8longn.c @@ -0,0 +1,13 @@ +#include "scan.h" + +size_t scan_8longn(const char *src,size_t n,unsigned long *dest) { + register const char *tmp=src; + register unsigned long l=0; + register unsigned char c; + while (n-->0 && (c=*tmp-'0')<8) { + l=l*8+c; + ++tmp; + } + *dest=l; + return tmp-src; +} diff --git a/scan/scan_longn.c b/scan/scan_longn.c new file mode 100644 index 0000000..c6e913e --- /dev/null +++ b/scan/scan_longn.c @@ -0,0 +1,23 @@ +#include "scan.h" + +size_t scan_longn(const char *src,size_t n,long *dest) { + register const char *tmp; + register long int l; + register unsigned char c; + int neg; + int ok; + if (!n--) return 0; + tmp=src; l=0; ok=neg=0; + switch (*tmp) { + case '-': neg=1; + case '+': ++tmp; + } + while (n-->0 && (c=*tmp-'0')<10) { + l=l*10+c; + ++tmp; + ok=1; + } + if (!ok) return 0; + *dest=(neg?-l:l); + return tmp-src; +} diff --git a/scan/scan_ulongn.c b/scan/scan_ulongn.c new file mode 100644 index 0000000..f611299 --- /dev/null +++ b/scan/scan_ulongn.c @@ -0,0 +1,25 @@ +#include "scan.h" + +size_t scan_ulongn(const char* src,size_t n,unsigned long int* dest) { + register const char *tmp=src; + register unsigned long int l=0; + register unsigned char c; + while (n-->0 && (c=*tmp-'0')<10) { + unsigned long int n; + /* we want to do: l=l*10+c + * but we need to check for integer overflow. + * to check whether l*10 overflows, we could do + * if ((l*10)/10 != l) + * however, multiplication and division are expensive. + * so instead of *10 we do (l<<3) (i.e. *8) + (l<<1) (i.e. *2) + * and check for overflow on all the intermediate steps */ + n=l<<3; if ((n>>3)!=l) break; + if (n+(l<<1) < n) break; + n+=l<<1; + if (n+c < n) break; + l=n+c; + ++tmp; + } + if (tmp-src) *dest=l; + return tmp-src; +} diff --git a/scan/scan_xlongn.c b/scan/scan_xlongn.c new file mode 100644 index 0000000..a24cf67 --- /dev/null +++ b/scan/scan_xlongn.c @@ -0,0 +1,13 @@ +#include "scan.h" + +size_t scan_xlongn(const char *src,size_t n,unsigned long *dest) { + register const char *tmp=src; + register unsigned long l=0; + register unsigned char c; + while (n-->0 && (c=scan_fromhex(*tmp))<16) { + l=(l<<4)+c; + ++tmp; + } + *dest=l; + return tmp-src; +}