add netstring formatter

fix scan_netstring to actually correctly return the length of the transported string
add documentation
master
leitner 9 years ago
parent fb1f19042f
commit 6859c4b6ca

35
fmt.h

@ -10,6 +10,8 @@
#include <sys/types.h> #include <sys/types.h>
/* for byte_copy */ /* for byte_copy */
#include "byte.h" #include "byte.h"
/* for add_of */
#include "rangecheck.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -143,10 +145,43 @@ size_t fmt_iso8601(char* dest,time_t t);
#define FMT_UTF8 5 #define FMT_UTF8 5
#define FMT_ASN1LENGTH 17 /* enough space to hold 2^128-1 */ #define FMT_ASN1LENGTH 17 /* enough space to hold 2^128-1 */
#define FMT_ASN1TAG 19 /* enough space to hold 2^128-1 */ #define FMT_ASN1TAG 19 /* enough space to hold 2^128-1 */
/* some variable length encodings for integers */ /* some variable length encodings for integers */
size_t fmt_utf8(char* dest,uint32_t n); /* can store 0-0x7fffffff */ size_t fmt_utf8(char* dest,uint32_t n); /* can store 0-0x7fffffff */
size_t fmt_asn1derlength(char* dest,unsigned long long l); /* 0-0x7f: 1 byte, above that 1+bytes_needed bytes */ size_t fmt_asn1derlength(char* dest,unsigned long long l); /* 0-0x7f: 1 byte, above that 1+bytes_needed bytes */
size_t fmt_asn1dertag(char* dest,unsigned long long l); /* 1 byte for each 7 bits; upper bit = more bytes coming */ size_t fmt_asn1dertag(char* dest,unsigned long long l); /* 1 byte for each 7 bits; upper bit = more bytes coming */
size_t fmt_varint(char* dest,unsigned long long l); /* protocol buffers encoding; like asn1dertag but little endian */
size_t fmt_pb_tag(char* dest,size_t fieldno,unsigned char type); /* protocol buffer tag */
size_t fmt_pb_type0_int(char* dest,signed long long l); /* protocol buffers encoding: type 0 integer */
size_t fmt_pb_type1_double(char* dest,double d); /* protocol buffers encoding: double (64-bit little endian blob) */
size_t fmt_pb_type1_fixed64(char* dest,uint64_t l); /* protocol buffers encoding: 64-bit little endian blob */
size_t fmt_pb_type2_string(char* dest,const char* s,size_t l); /* protocol buffers encoding: varint length + blob */
size_t fmt_pb_type5_float(char* dest,float f); /* protocol buffers encoding: float (32-bit little endian blob) */
size_t fmt_pb_type5_fixed32(char* dest,uint32_t l); /* protocol buffers encoding: 32-bit little endian blob */
static inline size_t fmt_pb_int(char* dest,size_t fieldno,signed long long l) {
size_t n=fmt_pb_tag(dest,fieldno,0);
return n+fmt_pb_type0_int(dest?dest+n:0,l);
}
static inline size_t fmt_pb_double(char* dest,size_t fieldno,double d) {
size_t n=fmt_pb_tag(dest,fieldno,1);
return n+fmt_pb_type1_double(dest?dest+n:0,d);
}
static inline size_t fmt_pb_float(char* dest,size_t fieldno,float f) {
size_t n=fmt_pb_tag(dest,fieldno,5);
return n+fmt_pb_type5_float(dest?dest+n:0,f);
}
static inline size_t fmt_pb_string(char* dest,size_t fieldno,const char* s,size_t l) {
size_t n=fmt_pb_tag(dest,fieldno,2);
size_t m;
if (add_of(m,fmt_pb_type2_string(NULL,s,l),n)) return 0;
return n+fmt_pb_type2_string(dest?dest+n:0,s,l);
}
size_t fmt_netstring(char* dest,const char* src,size_t len);
/* Marshaling helper functions. /* Marshaling helper functions.
* Escape one character, no matter if it needs escaping or not. * Escape one character, no matter if it needs escaping or not.

@ -0,0 +1,29 @@
.TH fmt_netstring 3
.SH NAME
fmt_netstring \- convert a memory buffer into a netstring
.SH SYNTAX
.B #include <fmt.h>
size_t \fBfmt_netstring\fP(char *\fIdest\fR,const char *\fIsource\fR,
size_t \fIlen\fR);
.SH DESCRIPTION
fmt_netstring creates a netstring from a raw memory buffer and returns
the length.
fmt_netstring does not append \\0.
If \fIdest\fR equals FMT_LEN (i.e. is zero), fmt_netstring returns the number
of bytes it would have written.
.SH "RETURN VALUE"
fmt_netstring returns the number of bytes written (or that would have
been written, had the destination pointer not pointed to NULL).
If the input buffer is implausibly large, fmt_netstring returns 0
instead.
.SH EXAMPLE
The raw memory buffer "foo" would become the netstring "3:foo,"
.SH SPEC
http://cr.yp.to/proto/netstrings.txt
.SH "SEE ALSO"
scan_netstring(3)

@ -0,0 +1,15 @@
#include "fmt.h"
#include "rangecheck.h"
#include <string.h>
size_t fmt_netstring(char* dest,const char* src,size_t len) {
size_t n=fmt_ulong(NULL,len);
size_t m;
if (!range_validbuf(src,len) || add_of(m,len,n+2)) return 0; /* n came from fmt_ulong, so it is a very small number, below 50 */
if (!dest) return m;
fmt_ulong(dest,len); dest+=n;
*dest++=':';
memcpy(dest,src,len);
dest[len]=',';
return m;
}

@ -0,0 +1,27 @@
.TH scan_netstring 3
.SH NAME
scan_netstring \- parse a netstring
.SH SYNTAX
.B #include <scan.h>
size_t \fBscan_netstring\fP(const char *\fIin\fR,size_t len,char** \fIdest\fR, size_t *\fIslen\fR);
.SH DESCRIPTION
scan_netstring attempts to parse the netstring in the input buffer
(in,len). If the buffer contains a valid netstring, then (*dest,*slen)
is set to the start and length of the transported string.
Note that this string is not zero terminated. No copy is made.
scan_netstring points it inside the input buffer.
.SH "RETURN VALUE"
scan_netstring returns the number of bytes in the netstring (the outer
representation, not the transported inner string) if parsing worked, or
0 if the input buffer did not contain a valid (or full) netstring.
.SH EXAMPLE
The raw memory buffer "foo" would become the netstring "3:foo,"
.SH SPEC
http://cr.yp.to/proto/netstrings.txt
.SH "SEE ALSO"
fmt_netstring(3)

@ -20,6 +20,6 @@ size_t scan_netstring(const char* in,size_t len,char** dest,size_t* slen) {
in[n+l+1]!=',') in[n+l+1]!=',')
return 0; return 0;
*dest=(char*)in+n+1; *dest=(char*)in+n+1;
*slen=n; *slen=l;
return n+2+l; return n+2+l;
} }

@ -0,0 +1,20 @@
#include "fmt.h"
#include "scan.h"
#include <assert.h>
#include <stdio.h>
int main() {
char buf[100];
char* s;
size_t l;
const char* orig;
assert(fmt_netstring(buf,"hello world!",12)==16 && !memcmp(buf,"12:hello world!,",16));
assert(scan_netstring(buf,16,&s,&l)==16 && s==buf+3 && l==12);
orig="3:foo,"; assert(scan_netstring(orig,6,&s,&l)==6 && s==orig+2 && l==3);
orig="4294967295:foo,"; assert(scan_netstring(orig,15,&s,&l)==0);
orig="18446744073709551615:foo,"; assert(scan_netstring(orig,25,&s,&l)==0);
assert(fmt_netstring(buf,orig,(size_t)-1)==0);
assert(fmt_netstring(buf,NULL,(size_t)-1)==0);
}

@ -1,11 +0,0 @@
#include "scan.h"
#include <assert.h>
int main() {
char* s;
size_t l;
const char* orig;
orig="3:foo,"; assert(scan_netstring(orig,6,&s,&l)==6); assert(s==orig+2);
orig="4294967295:foo,"; assert(scan_netstring(orig,15,&s,&l)==0);
orig="18446744073709551615:foo,"; assert(scan_netstring(orig,25,&s,&l)==0);
}
Loading…
Cancel
Save