Change the translation of the "Help" menu item to "?", so that the menu can be displa...
[reactos.git] / rosapps / smartpdf / baseutils / netstr.c
1 /* Written by Krzysztof Kowalczyk (http://blog.kowalczyk.info)
2 The author disclaims copyright to this source code. */
3 #include "base_util.h"
4 #include "tstr_util.h"
5 #include "netstr.h"
6
7 /* Implements djb idea of net strings */
8 /* Return the number of digits needed to represents a given number in base 10
9 string representation.
10 */
11 size_t digits_for_number(int num)
12 {
13 size_t digits = 1;
14 /* negative numbers need '-' in front of them */
15 if (num < 0) {
16 ++digits;
17 num = -num;
18 }
19
20 while (num >= 10)
21 {
22 ++digits;
23 num = num / 10;
24 }
25 return digits;
26 }
27
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)
32 - data
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)
36 */
37 size_t netstr_tstrn_serialized_len_cb(size_t str_len_cch)
38 {
39 size_t total_len_cch;
40
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);
44 }
45
46 /* Return number of bytes needed to serialize string 'str' in netstring format. */
47 size_t netstr_tstr_serialized_len_cb(const TCHAR *str)
48 {
49 size_t str_len_cch;
50
51 if (!str) return 0;
52 str_len_cch = tstr_len(str);
53 return netstr_tstrn_serialized_len_cb(str_len_cch);
54 }
55
56 /* Return number of bytes needed to serialize integer 'num' in netstring format. */
57 size_t netstr_int_serialized_len_cb(int num)
58 {
59 size_t str_len_cch;
60 size_t total_len_cch;
61
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);
65 }
66
67 int netstr_tstr_serialize(const TCHAR *str, TCHAR **buf_ptr, size_t *buf_len_cb_ptr)
68 {
69 char * buf;
70 size_t buf_len_cb;
71 size_t len_needed_cb;
72 TCHAR * num_str;
73 size_t str_len_cch;
74 size_t len_cb;
75 size_t total_len_cb = 0;
76
77 assert(buf_len_cb_ptr);
78 if (!buf_len_cb_ptr)
79 return FALSE;
80
81 if (!buf_ptr)
82 {
83 *buf_len_cb_ptr += netstr_tstr_serialized_len_cb(str);
84 return TRUE;
85 }
86
87 buf = (char*)*buf_ptr;
88 assert(buf);
89 if (!buf)
90 return FALSE;
91
92 buf_len_cb = *buf_len_cb_ptr;
93 assert(buf_len_cb > 0);
94 if (buf_len_cb <= 0)
95 return FALSE;
96
97 len_needed_cb = netstr_tstr_serialized_len_cb(str);
98 if (len_needed_cb > buf_len_cb)
99 return FALSE;
100
101 str_len_cch = tstr_len(str);
102 num_str = tstr_printf(_T("%d:"), str_len_cch);
103 if (!num_str)
104 return FALSE;
105
106 len_cb = tstr_len(num_str)*sizeof(TCHAR);
107 memcpy(buf, num_str, len_cb);
108 buf += 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);
113 buf += 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);
118 buf += len_cb;
119 total_len_cb += len_cb;
120 assert(total_len_cb == len_needed_cb);
121
122 *buf_len_cb_ptr -= total_len_cb;
123 *buf_ptr = (TCHAR*)buf;
124 free((void*)num_str);
125 return TRUE;
126 }
127
128 int netstr_int_serialize(int num, TCHAR **buf_ptr, size_t *buf_len_cb_ptr)
129 {
130 TCHAR * num_str;
131 int f_ok;
132
133 assert(buf_len_cb_ptr);
134 if (!buf_len_cb_ptr)
135 return FALSE;
136
137 if (!buf_ptr)
138 {
139 *buf_len_cb_ptr += netstr_int_serialized_len_cb(num);
140 return TRUE;
141 }
142
143 num_str = tstr_printf(_T("%d"), num);
144 if (!num_str)
145 return FALSE;
146
147 f_ok = netstr_tstr_serialize(num_str, buf_ptr, buf_len_cb_ptr);
148 free((void*)num_str);
149 return f_ok;
150 }
151
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)
155 {
156 int num = 0;
157 const TCHAR * tmp;
158 size_t str_len_cb;
159 TCHAR c;
160 int digit = 0;
161
162 assert(str_ptr);
163 if (!str_ptr)
164 return FALSE;
165 assert(str_len_cb_ptr);
166 if (!str_len_cb_ptr)
167 return FALSE;
168 assert(num_out);
169 if (!num_out)
170 return FALSE;
171
172 tmp = *str_ptr;
173 assert(tmp);
174 if (!tmp)
175 return FALSE;
176
177 str_len_cb = *str_len_cb_ptr;
178 assert(str_len_cb > 0);
179 if (str_len_cb <= 0)
180 return FALSE;
181
182 for (;;) {
183 str_len_cb -= sizeof(TCHAR);
184 if (str_len_cb < 0)
185 return FALSE;
186 c = *tmp++;
187 if (_T(':') == c)
188 break;
189 if ( (c >= _T('0')) && (c <= _T('9')) )
190 digit = (int)c - _T('0');
191 else
192 return FALSE;
193 num = (num * 10) + digit;
194 }
195 if (str_len_cb == *str_len_cb_ptr)
196 return FALSE;
197
198 *str_ptr = tmp;
199 *str_len_cb_ptr = str_len_cb;
200 *num_out = num;
201 return TRUE;
202 }
203
204 int netstr_valid_separator(TCHAR c)
205 {
206 if (c == _T(','))
207 return TRUE;
208 return FALSE;
209 }
210
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)
212 {
213 int f_ok;
214 size_t str_len_cch;
215 size_t str_len_cb;
216 const TCHAR * str;
217 const TCHAR * str_copy;
218 int num;
219
220 f_ok = netstr_get_str_len(str_ptr, str_len_cb_ptr, &num);
221 if (!f_ok)
222 return FALSE;
223 assert(num >= 0);
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)
227 return FALSE;
228
229 str = *str_ptr;
230 if (!netstr_valid_separator(str[str_len_cch]))
231 return FALSE;
232 str_copy = (const TCHAR*)tstr_dupn(str, str_len_cch);
233 if (!str_copy)
234 return FALSE;
235 *str_out = str_copy;
236 *str_len_cch_out = str_len_cch;
237 *str_ptr = str + str_len_cch + 1;
238 *str_len_cb_ptr -= str_len_cb ;
239 return TRUE;
240 }
241
242 int netstr_parse_int(const TCHAR **str_ptr, size_t *str_len_cb_ptr, int *int_out)
243 {
244 const TCHAR * str = NULL;
245 const TCHAR * tmp;
246 TCHAR c;
247 size_t str_len_cch;
248 int f_ok;
249 int num = 0;
250 int digit = 0;
251
252 f_ok = netstr_parse_str(str_ptr, str_len_cb_ptr, &str, &str_len_cch);
253 if (!f_ok)
254 return FALSE;
255
256 tmp = str;
257 while (*tmp) {
258 c = *tmp++;
259 if ( (c >= _T('0')) && (c <= _T('9')) )
260 digit = (int)c - _T('0');
261 else
262 goto Error;
263 num = (num * 10) + digit;
264 }
265 *int_out = num;
266 free((void*)str);
267 return TRUE;
268 Error:
269 free((void*)str);
270 return FALSE;
271 }