1 /* Written by Krzysztof Kowalczyk (http://blog.kowalczyk.info)
2 The author disclaims copyright to this source code. */
7 /* Implements djb idea of net strings */
8 /* Return the number of digits needed to represents a given number in base 10
11 size_t digits_for_number(int num
)
14 /* negative numbers need '-' in front of them */
28 /* Netstring format is a safe, easy and mostly human readable format for
29 serializing strings (well, any binary data). Netstring format is:
30 - a byte length of the data as a string
31 - ':' (single character)
33 - ',' (single character)
34 e.g. "foo" is encoded as "3:foo,"
35 I learned about netstring format from djb (http://cr.yp.to/proto/netstrings.txt)
37 size_t netstr_tstrn_serialized_len_cb(size_t str_len_cch
)
41 /* 2 is for ':" and ',' */
42 total_len_cch
= str_len_cch
+ digits_for_number((int)str_len_cch
) + 2;
43 return total_len_cch
* sizeof(TCHAR
);
46 /* Return number of bytes needed to serialize string 'str' in netstring format. */
47 size_t netstr_tstr_serialized_len_cb(const TCHAR
*str
)
52 str_len_cch
= tstr_len(str
);
53 return netstr_tstrn_serialized_len_cb(str_len_cch
);
56 /* Return number of bytes needed to serialize integer 'num' in netstring format. */
57 size_t netstr_int_serialized_len_cb(int num
)
62 str_len_cch
= digits_for_number(num
);
63 total_len_cch
= str_len_cch
+ digits_for_number((int)str_len_cch
) + 2;
64 return total_len_cch
* sizeof(TCHAR
);
67 int netstr_tstr_serialize(const TCHAR
*str
, TCHAR
**buf_ptr
, size_t *buf_len_cb_ptr
)
75 size_t total_len_cb
= 0;
77 assert(buf_len_cb_ptr
);
83 *buf_len_cb_ptr
+= netstr_tstr_serialized_len_cb(str
);
87 buf
= (char*)*buf_ptr
;
92 buf_len_cb
= *buf_len_cb_ptr
;
93 assert(buf_len_cb
> 0);
97 len_needed_cb
= netstr_tstr_serialized_len_cb(str
);
98 if (len_needed_cb
> buf_len_cb
)
101 str_len_cch
= tstr_len(str
);
102 num_str
= tstr_printf(_T("%d:"), str_len_cch
);
106 len_cb
= tstr_len(num_str
)*sizeof(TCHAR
);
107 memcpy(buf
, num_str
, len_cb
);
109 total_len_cb
+= len_cb
;
110 assert(total_len_cb
<= len_needed_cb
);
111 len_cb
= tstr_len(str
)*sizeof(TCHAR
);
112 memcpy(buf
, str
, len_cb
);
114 total_len_cb
+= len_cb
;
115 assert(total_len_cb
<= len_needed_cb
);
116 len_cb
= sizeof(TCHAR
);
117 memcpy(buf
, _T(","), len_cb
);
119 total_len_cb
+= len_cb
;
120 assert(total_len_cb
== len_needed_cb
);
122 *buf_len_cb_ptr
-= total_len_cb
;
123 *buf_ptr
= (TCHAR
*)buf
;
124 free((void*)num_str
);
128 int netstr_int_serialize(int num
, TCHAR
**buf_ptr
, size_t *buf_len_cb_ptr
)
133 assert(buf_len_cb_ptr
);
139 *buf_len_cb_ptr
+= netstr_int_serialized_len_cb(num
);
143 num_str
= tstr_printf(_T("%d"), num
);
147 f_ok
= netstr_tstr_serialize(num_str
, buf_ptr
, buf_len_cb_ptr
);
148 free((void*)num_str
);
152 /* Parse a netstring number i.e. a list of digits until ':', skipping ':'.
153 Returns FALSE if there's an error parsing (string doesn't follow the format) */
154 static int netstr_get_str_len(const TCHAR
**str_ptr
, size_t *str_len_cb_ptr
, int *num_out
)
165 assert(str_len_cb_ptr
);
177 str_len_cb
= *str_len_cb_ptr
;
178 assert(str_len_cb
> 0);
183 str_len_cb
-= sizeof(TCHAR
);
189 if ( (c
>= _T('0')) && (c
<= _T('9')) )
190 digit
= (int)c
- _T('0');
193 num
= (num
* 10) + digit
;
195 if (str_len_cb
== *str_len_cb_ptr
)
199 *str_len_cb_ptr
= str_len_cb
;
204 int netstr_valid_separator(TCHAR c
)
211 int netstr_parse_str(const TCHAR
**str_ptr
, size_t *str_len_cb_ptr
, const TCHAR
**str_out
, size_t *str_len_cch_out
)
217 const TCHAR
* str_copy
;
220 f_ok
= netstr_get_str_len(str_ptr
, str_len_cb_ptr
, &num
);
224 str_len_cch
= (size_t)num
;
225 str_len_cb
= (str_len_cch
+1)*sizeof(TCHAR
);
226 if (str_len_cb
> *str_len_cb_ptr
)
230 if (!netstr_valid_separator(str
[str_len_cch
]))
232 str_copy
= (const TCHAR
*)tstr_dupn(str
, str_len_cch
);
236 *str_len_cch_out
= str_len_cch
;
237 *str_ptr
= str
+ str_len_cch
+ 1;
238 *str_len_cb_ptr
-= str_len_cb
;
242 int netstr_parse_int(const TCHAR
**str_ptr
, size_t *str_len_cb_ptr
, int *int_out
)
244 const TCHAR
* str
= NULL
;
252 f_ok
= netstr_parse_str(str_ptr
, str_len_cb_ptr
, &str
, &str_len_cch
);
259 if ( (c
>= _T('0')) && (c
<= _T('9')) )
260 digit
= (int)c
- _T('0');
263 num
= (num
* 10) + digit
;