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