1 /* $Id$ */
2 
3 /*
4  *  (C) Copyright 2012 Tomek Wasilczyk <www.wasilczyk.pl>
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU Lesser General Public License Version
8  *  2.1 as published by the Free Software Foundation.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU Lesser General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Lesser General Public
16  *  License along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
18  *  USA.
19  */
20 
21 /**
22  * \file tvbuff.c
23  *
24  * \brief Bufor wspierający obsługę pakietów typu Type-Value(s)
25  */
26 
27 #include <stdlib.h>
28 #include <string.h>
29 
30 #include "tvbuff.h"
31 
32 #include "internal.h"
33 
34 struct gg_tvbuff
35 {
36 	const char *buffer;
37 	size_t length;
38 	size_t offset;
39 	int valid;
40 };
41 
42 /**
43  * \internal Tworzy nową instancję bufora.
44  *
45  * \param buffer Bufor źródłowy; nie może być modyfikowany (w szczególności
46  *        zwalniany) przez cały okres korzystania z jego opakowanej wersji.
47  * \param length Długość bufora źródłowego.
48  *
49  * \return Zaalokowane opakowanie bufora - musi być zwolnione przez free lub
50  *         gg_tvbuff_close.
51  */
gg_tvbuff_new(const char * buffer,size_t length)52 gg_tvbuff_t *gg_tvbuff_new(const char *buffer, size_t length)
53 {
54 	gg_tvbuff_t *tvb;
55 
56 	tvb = malloc(sizeof(gg_tvbuff_t));
57 	if (tvb == NULL)
58 		return NULL;
59 	memset(tvb, 0, sizeof(gg_tvbuff_t));
60 
61 	if (buffer == NULL && length > 0) {
62 		gg_debug(GG_DEBUG_ERROR, "// gg_tvbuff_new() "
63 			"invalid arguments\n");
64 		tvb->valid = 0;
65 		return tvb;
66 	}
67 
68 	tvb->buffer = buffer;
69 	tvb->length = length;
70 	tvb->offset = 0;
71 	tvb->valid = 1;
72 
73 	return tvb;
74 }
75 
76 /**
77  * \internal Zwalnia opakowanie bufora. Przed zwolnieniem sprawdza, czy
78  * przeczytano go do końca.
79  *
80  * \param tvb Bufor.
81  *
82  * \return Wartość różna od 0, jeżeli bufor tuż przed zwolnieniem był oznaczony
83  *         jako prawidłowy
84  */
gg_tvbuff_close(gg_tvbuff_t * tvb)85 int gg_tvbuff_close(gg_tvbuff_t *tvb)
86 {
87 	int valid;
88 
89 	gg_tvbuff_expected_eob(tvb);
90 	valid = gg_tvbuff_is_valid(tvb);
91 	free(tvb);
92 
93 	return valid;
94 }
95 
96 /**
97  * \internal Sprawdza, czy wszystkie odczyty z bufora były prawidłowe.
98  *
99  * \param tvb Bufor.
100  *
101  * \return Wartość różna od 0, jeżeli wszystkie odczyty były prawidłowe.
102  */
gg_tvbuff_is_valid(const gg_tvbuff_t * tvb)103 int gg_tvbuff_is_valid(const gg_tvbuff_t *tvb)
104 {
105 	if (tvb == NULL)
106 		return 0;
107 	return tvb->valid;
108 }
109 
110 /**
111  * \internal Zwraca pozostałą do odczytania liczbę bajtów w buforze.
112  *
113  * \param tvb Bufor.
114  *
115  * \return Pozostała liczba bajtów do odczytania.
116  */
gg_tvbuff_get_remaining(const gg_tvbuff_t * tvb)117 size_t gg_tvbuff_get_remaining(const gg_tvbuff_t *tvb)
118 {
119 	if (!gg_tvbuff_is_valid(tvb))
120 		return 0;
121 
122 	return tvb->length - tvb->offset;
123 }
124 
125 /**
126  * \internal Sprawdza, czy w buforze pozostała określona liczba bajtów do
127  * odczytania. Jeżeli nie została - oznacza bufor jako nieprawidłowy.
128  *
129  * \param tvb    Bufor.
130  * \param length Ilość bajtów do odczytania.
131  *
132  * \return Wartość różna od 0, jeżeli można odczytać podaną liczbę bajtów.
133  */
gg_tvbuff_have_remaining(gg_tvbuff_t * tvb,size_t length)134 int gg_tvbuff_have_remaining(gg_tvbuff_t *tvb, size_t length)
135 {
136 	if (!gg_tvbuff_is_valid(tvb))
137 		return 0;
138 
139 	if (gg_tvbuff_get_remaining(tvb) >= length)
140 		return 1;
141 
142 	gg_debug(GG_DEBUG_WARNING, "// gg_tvbuff_have_remaining() failed "
143 		"(%" GG_SIZE_FMT " < %" GG_SIZE_FMT ")\n",
144 		gg_tvbuff_get_remaining(tvb), length);
145 	tvb->valid = 0;
146 	return 0;
147 }
148 
149 /**
150  * \internal Pomija określoną liczbę bajtów w buforze. Jeżeli w wyniku ich
151  * pominięcia wyjdzie poza zakres, oznacza bufor jako nieprawidłowy.
152  *
153  * \param tvb    Bufor
154  * \param amount Liczba bajtów do pominięcia
155  */
gg_tvbuff_skip(gg_tvbuff_t * tvb,size_t amount)156 void gg_tvbuff_skip(gg_tvbuff_t *tvb, size_t amount)
157 {
158 	if (!gg_tvbuff_is_valid(tvb))
159 		return;
160 
161 	if (tvb->offset + amount > tvb->length) {
162 		gg_debug(GG_DEBUG_WARNING, "// gg_tvbuff_skip() failed\n");
163 		tvb->valid = 0;
164 		return;
165 	}
166 
167 	tvb->offset += amount;
168 }
169 
170 /**
171  * \internal Cofa się o określoną liczbę bajtów w buforze. Jeżeli cofnie przed
172  * pierwszy znak, oznacza bufor jako nieprawidłowy.
173  *
174  * \param tvb    Bufor
175  * \param amount Liczba bajtów do cofnięcia
176  */
gg_tvbuff_rewind(gg_tvbuff_t * tvb,size_t amount)177 void gg_tvbuff_rewind(gg_tvbuff_t *tvb, size_t amount)
178 {
179 	if (!gg_tvbuff_is_valid(tvb))
180 		return;
181 
182 	if (tvb->offset < amount) {
183 		gg_debug(GG_DEBUG_WARNING, "// gg_tvbuff_rewind() failed\n");
184 		tvb->valid = 0;
185 		return;
186 	}
187 
188 	tvb->offset -= amount;
189 }
190 
191 /**
192  * \internal Sprawdza, czy pod aktualną pozycją w buforze występuje podana
193  * wartość. Jeżeli tak, przesuwa aktualną pozycję do przodu.
194  *
195  * \param tvb   Bufor.
196  * \param value Wartość do sprawdzenia
197  *
198  * \return Wartość różna od 0, jeżeli znaleziono podaną wartość.
199  */
gg_tvbuff_match(gg_tvbuff_t * tvb,uint8_t value)200 int gg_tvbuff_match(gg_tvbuff_t *tvb, uint8_t value)
201 {
202 	if (!gg_tvbuff_is_valid(tvb))
203 		return 0;
204 
205 	if (!gg_tvbuff_have_remaining(tvb, 1)) {
206 		gg_debug(GG_DEBUG_WARNING, "// gg_tvbuff_match() failed\n");
207 		return 0;
208 	}
209 
210 	if (tvb->buffer[tvb->offset] != value)
211 		return 0;
212 
213 	tvb->offset++;
214 	return 1;
215 }
216 
217 /**
218  * \internal Odczytuje z bufora liczbę 8-bitową.
219  *
220  * \param tvb Bufor
221  *
222  * \return Odczytana liczba
223  */
gg_tvbuff_read_uint8(gg_tvbuff_t * tvb)224 uint8_t gg_tvbuff_read_uint8(gg_tvbuff_t *tvb)
225 {
226 	if (!gg_tvbuff_is_valid(tvb))
227 		return 0;
228 
229 	if (!gg_tvbuff_have_remaining(tvb, 1)) {
230 		gg_debug(GG_DEBUG_WARNING, "// gg_tvbuff_read_uint8() "
231 			"failed at %" GG_SIZE_FMT "\n", tvb->offset);
232 		return 0;
233 	}
234 
235 	return tvb->buffer[tvb->offset++];
236 }
237 
238 /**
239  * \internal Odczytuje z bufora liczbę 32-bitową.
240  *
241  * \param tvb Bufor
242  *
243  * \return Odczytana liczba
244  */
gg_tvbuff_read_uint32(gg_tvbuff_t * tvb)245 uint32_t gg_tvbuff_read_uint32(gg_tvbuff_t *tvb)
246 {
247 	uint32_t val;
248 
249 	if (!gg_tvbuff_is_valid(tvb))
250 		return 0;
251 
252 	if (!gg_tvbuff_have_remaining(tvb, 4)) {
253 		gg_debug(GG_DEBUG_WARNING, "// gg_tvbuff_read_uint32() "
254 			"failed at %" GG_SIZE_FMT "\n", tvb->offset);
255 		return 0;
256 	}
257 
258 	memcpy(&val, tvb->buffer + tvb->offset, 4);
259 	tvb->offset += 4;
260 
261 	return gg_fix32(val);
262 }
263 
264 /**
265  * \internal Odczytuje z bufora liczbę 64-bitową.
266  *
267  * \param tvb Bufor
268  *
269  * \return Odczytana liczba
270  */
gg_tvbuff_read_uint64(gg_tvbuff_t * tvb)271 uint64_t gg_tvbuff_read_uint64(gg_tvbuff_t *tvb)
272 {
273 	uint64_t val;
274 
275 	if (!gg_tvbuff_is_valid(tvb))
276 		return 0;
277 
278 	if (!gg_tvbuff_have_remaining(tvb, 8)) {
279 		gg_debug(GG_DEBUG_WARNING, "// gg_tvbuff_read_uint64() "
280 			"failed at %" GG_SIZE_FMT "\n", tvb->offset);
281 		return 0;
282 	}
283 
284 	memcpy(&val, tvb->buffer + tvb->offset, 8);
285 	tvb->offset += 8;
286 
287 	return gg_fix64(val);
288 }
289 
290 /**
291  * \internal Odczytuje z bufora skompresowaną liczbę całkowitą.
292  * Liczba taka może być zapisana w buforze na 1-9 bajtach, w zależności
293  * od jej wartości.
294  *
295  * Skompresowana liczba jest zapisywana od najmłodszego bajtu do najstarszego
296  * niezerowego. W każdym bajcie zapisuje się bit sterujący (równy 0, jeżeli jest
297  * to ostatni bajt do przeczytania, lub 1 w p.p.) oraz 7 kolejnych bitów z
298  * kompresowanej liczby.
299  *
300  * Przykładowo, liczby mniejsze od 128 (1000.0000b) są zapisywane dokładnie tak,
301  * jak uint8_t; a np. 12345 (0011.0000.0011.1001b) zostanie zapisana jako 0x60B9
302  * (0110.0000.1011.1001b).
303  *
304  * \param tvb Bufor.
305  *
306  * \return Odczytana liczba.
307  */
gg_tvbuff_read_packed_uint(gg_tvbuff_t * tvb)308 uint64_t gg_tvbuff_read_packed_uint(gg_tvbuff_t *tvb)
309 {
310 	uint64_t val = 0;
311 	int i, val_len = 0;
312 
313 	if (!gg_tvbuff_is_valid(tvb))
314 		return 0;
315 
316 	while (gg_tvbuff_have_remaining(tvb, 1)) {
317 		val_len++;
318 		if (!(gg_tvbuff_read_uint8(tvb) & 0x80))
319 			break;
320 	}
321 
322 	if (!gg_tvbuff_is_valid(tvb)) {
323 		gg_debug(GG_DEBUG_WARNING,
324 			"// gg_tvbuff_read_packed_uint() failed\n");
325 		return 0;
326 	}
327 
328 	if (val_len > 9) {
329 		gg_debug(GG_DEBUG_WARNING, "// gg_tvbuff_read_packed_uint() "
330 			"packed uint size too big: %d\n", val_len);
331 		tvb->valid = 0;
332 		return 0;
333 	}
334 
335 	for (i = 1; i <= val_len; i++) {
336 		uint64_t old_val = val;
337 		val <<= 7;
338 		if (old_val != (val >> 7)) {
339 			gg_debug(GG_DEBUG_WARNING,
340 				"// gg_tvbuff_read_packed_uint() overflow\n");
341 			tvb->valid = 0;
342 			return 0;
343 		}
344 		val |= (uint8_t)(tvb->buffer[tvb->offset - i] & ~0x80);
345 	}
346 
347 	return val;
348 }
349 
350 /**
351  * \internal Odczytuje z bufora podciąg bez kopiowania danych.
352  *
353  * \param tvb    Bufor źródłowy
354  * \param length Ilość bajtów do odczytania
355  *
356  * \return Wskaźnik na początek odczytanych danych, lub NULL w przypadku
357  *         niepowodzenia
358  */
gg_tvbuff_read_buff(gg_tvbuff_t * tvb,size_t length)359 const char *gg_tvbuff_read_buff(gg_tvbuff_t *tvb, size_t length)
360 {
361 	const char *buff;
362 
363 	if (!gg_tvbuff_is_valid(tvb))
364 		return NULL;
365 
366 	if (!gg_tvbuff_have_remaining(tvb, length)) {
367 		gg_debug(GG_DEBUG_WARNING, "// gg_tvbuff_get_buff() "
368 			"failed at %" GG_SIZE_FMT ":%" GG_SIZE_FMT "\n",
369 			tvb->offset, length);
370 		return NULL;
371 	}
372 
373 	buff = tvb->buffer + tvb->offset;
374 	tvb->offset += length;
375 	return buff;
376 }
377 
378 /**
379  * \internal Odczytuje z bufora podciąg kopiując go do nowego obszaru pamięci.
380  *
381  * \param tvb    Bufor źródłowy
382  * \param buffer Bufor docelowy
383  * \param length Ilość bajtów do odczytania
384  */
gg_tvbuff_read_buff_cpy(gg_tvbuff_t * tvb,char * buffer,size_t length)385 void gg_tvbuff_read_buff_cpy(gg_tvbuff_t *tvb, char *buffer, size_t length)
386 {
387 	if (!gg_tvbuff_is_valid(tvb))
388 		return;
389 
390 	if (!gg_tvbuff_have_remaining(tvb, length)) {
391 		gg_debug(GG_DEBUG_WARNING, "// gg_tvbuff_read_buff() "
392 			"failed at %" GG_SIZE_FMT ":%" GG_SIZE_FMT "\n",
393 			tvb->offset, length);
394 		return;
395 	}
396 
397 	if (buffer == NULL && length > 0) {
398 		gg_debug(GG_DEBUG_ERROR, "// gg_tvbuff_new() "
399 			"invalid arguments\n");
400 		tvb->valid = 0;
401 		return;
402 	}
403 
404 	memcpy(buffer, tvb->buffer + tvb->offset, length);
405 	tvb->offset += length;
406 }
407 
408 /**
409  * \internal Odczytuje z bufora ciąg tekstowy (mogący zawierać dowolne znaki,
410  * również \0) bez kopiowania danych.
411  *
412  * \param tvb    Bufor źródłowy
413  * \param length Zmienna, do której zostanie zapisana długość odczytanego ciągu
414  *
415  * \return Wskaźnik na początek odczytanych danych, lub NULL w przypadku
416  *         niepowodzenia
417  */
gg_tvbuff_read_str(gg_tvbuff_t * tvb,size_t * length)418 const char *gg_tvbuff_read_str(gg_tvbuff_t *tvb, size_t *length)
419 {
420 	size_t offset;
421 	uint32_t str_len;
422 	const char *str;
423 
424 	if (!gg_tvbuff_is_valid(tvb))
425 		return NULL;
426 
427 	offset = tvb->offset;
428 	str_len = gg_tvbuff_read_packed_uint(tvb);
429 	if (!gg_tvbuff_is_valid(tvb) ||
430 		!gg_tvbuff_have_remaining(tvb, str_len))
431 	{
432 		gg_debug(GG_DEBUG_WARNING, "// gg_tvbuff_read_str() failed at "
433 			"%" GG_SIZE_FMT ":%d\n", offset, str_len);
434 		return NULL;
435 	}
436 
437 	str = gg_tvbuff_read_buff(tvb, str_len);
438 
439 	if (!gg_tvbuff_is_valid(tvb))
440 		return NULL;
441 
442 	if (length != NULL)
443 		*length = str_len;
444 	if (str_len == 0)
445 		return NULL;
446 	return str;
447 }
448 
449 /**
450  * \internal Odczytuje z bufora ciąg tekstowy (mogący zawierać dowolne znaki,
451  * również \0) kopiując go do nowego obszaru pamięci. Zwrócony ciąg będzie
452  * zawsze zakończony znakiem \0.
453  *
454  * \param tvb Bufor źródłowy
455  * \param dst Zmienna, do której zostanie zapisany wskaźnik na odczytany ciąg.
456  *            Po użyciu, blok ten powinien zostać zwolniony za pomocą \c free()
457  *
458  * \return Wskaźnik na początek odczytanych danych, lub NULL w przypadku
459  *         niepowodzenia
460  */
gg_tvbuff_read_str_dup(gg_tvbuff_t * tvb,char ** dst)461 void gg_tvbuff_read_str_dup(gg_tvbuff_t *tvb, char **dst)
462 {
463 	size_t offset;
464 	uint32_t str_len;
465 	char *str;
466 
467 	if (!gg_tvbuff_is_valid(tvb))
468 		return;
469 
470 	offset = tvb->offset;
471 	str_len = gg_tvbuff_read_packed_uint(tvb);
472 	if (!gg_tvbuff_is_valid(tvb) ||
473 		!gg_tvbuff_have_remaining(tvb, str_len))
474 	{
475 		gg_debug(GG_DEBUG_WARNING, "// gg_tvbuff_read_str_dup() failed "
476 			"at %" GG_SIZE_FMT ":%d\n", offset, str_len);
477 		return;
478 	}
479 
480 	str = malloc(str_len + 1);
481 	if (str == NULL) {
482 		gg_debug(GG_DEBUG_ERROR, "// gg_tvbuff_read_str_dup() "
483 			"not enough free memory: %d + 1\n", str_len);
484 		tvb->valid = 0;
485 		return;
486 	}
487 
488 	gg_tvbuff_read_buff_cpy(tvb, str, str_len);
489 	str[str_len] = '\0';
490 
491 	if (*dst != NULL) {
492 		gg_debug(GG_DEBUG_WARNING, "// gg_tvbuff_read_str_dup() "
493 			"destination already filled, freeing it...\n");
494 		free(*dst);
495 	}
496 	*dst = str;
497 }
498 
499 /**
500  * \internal Odczytuje z bufora identyfikator użytkownika.
501  *
502  * \param tvb Bufor
503  *
504  * \return Identyfikator użytkownika, lub 0 w przypadku niepowodzenia
505  */
gg_tvbuff_read_uin(gg_tvbuff_t * tvb)506 uin_t gg_tvbuff_read_uin(gg_tvbuff_t *tvb)
507 {
508 	uin_t uin = 0;
509 	uint32_t uin_len, full_len;
510 	uint8_t uin_type;
511 	const char *raw;
512 
513 	if (!gg_tvbuff_is_valid(tvb))
514 		return 0;
515 
516 	full_len = gg_tvbuff_read_packed_uint(tvb);
517 	uin_type = gg_tvbuff_read_uint8(tvb);
518 	uin_len = gg_tvbuff_read_uint8(tvb);
519 
520 	if (!gg_tvbuff_is_valid(tvb))
521 		return 0;
522 
523 	if (full_len != uin_len + 2 ||
524 		uin_type != 0 ||
525 		uin_len > 10)
526 	{
527 		gg_debug(GG_DEBUG_WARNING, "// gg_tvbuff_read_uin() failed (1)\n");
528 		tvb->valid = 0;
529 		return 0;
530 	}
531 
532 	raw = gg_tvbuff_read_buff(tvb, uin_len);
533 	if (raw)
534 		uin = gg_str_to_uin(raw, uin_len);
535 
536 	if (uin == 0) {
537 		gg_debug(GG_DEBUG_WARNING, "// gg_tvbuff_read_uin() failed (2)\n");
538 		tvb->valid = 0;
539 		return 0;
540 	}
541 
542 	return uin;
543 }
544 
545 /**
546  * \internal Odczytuje z bufora liczbę 8-bitową i porównuje z podaną. Jeżeli te
547  * się różnią, zostaje wygenerowane ostrzeżenie.
548  *
549  * \param tvb   Bufor
550  * \param value Oczekiwana wartość
551  */
gg_tvbuff_expected_uint8(gg_tvbuff_t * tvb,uint8_t value)552 void gg_tvbuff_expected_uint8(gg_tvbuff_t *tvb, uint8_t value)
553 {
554 	uint8_t got;
555 	size_t offset;
556 
557 	offset = tvb->offset;
558 	got = gg_tvbuff_read_uint8(tvb);
559 	if (!gg_tvbuff_is_valid(tvb))
560 		return;
561 
562 	if (got != value)
563 		gg_debug(GG_DEBUG_WARNING, "// gg_tvbuff_expected_uint8() "
564 			"expected %#02x, but %#02x found at %" GG_SIZE_FMT "\n",
565 			value, got, offset);
566 }
567 
568 /**
569  * \internal Odczytuje z bufora liczbę 32-bitową i porównuje z podaną. Jeżeli te
570  * się różnią, zostaje wygenerowane ostrzeżenie.
571  *
572  * \param tvb   Bufor
573  * \param value Oczekiwana wartość
574  */
gg_tvbuff_expected_uint32(gg_tvbuff_t * tvb,uint32_t value)575 void gg_tvbuff_expected_uint32(gg_tvbuff_t *tvb, uint32_t value)
576 {
577 	uint32_t got;
578 	size_t offset;
579 
580 	offset = tvb->offset;
581 	got = gg_tvbuff_read_uint32(tvb);
582 	if (!gg_tvbuff_is_valid(tvb))
583 		return;
584 
585 	if (got != value)
586 		gg_debug(GG_DEBUG_WARNING, "// gg_tvbuff_expected_uint32() "
587 			"expected %#08x, but %#08x found at %" GG_SIZE_FMT "\n",
588 			value, got, offset);
589 }
590 
591 /**
592  * \internal Oczekuje końca bufora. Jeżeli w buforze są jeszcze dane do
593  * przeczytania, generuje ostrzeżenie.
594  *
595  * \param tvb Bufor.
596  */
gg_tvbuff_expected_eob(const gg_tvbuff_t * tvb)597 void gg_tvbuff_expected_eob(const gg_tvbuff_t *tvb)
598 {
599 	if (!gg_tvbuff_is_valid(tvb))
600 		return;
601 
602 	if (gg_tvbuff_get_remaining(tvb) != 0)
603 		gg_debug(GG_DEBUG_WARNING, "// gg_tvbuff_expected_eob() "
604 			"unexpected %" GG_SIZE_FMT " bytes, first=%#02x\n",
605 			gg_tvbuff_get_remaining(tvb),
606 			tvb->buffer[tvb->offset]);
607 }
608