comparison src/protocols/gg/lib/common.c @ 11360:cf15c1cdcfbd

[gaim-migrate @ 13582] New Gadu-Gadu implementation. committer: Tailor Script <tailor@pidgin.im>
author Bartoz Oler <bartosz@pidgin.im>
date Sun, 28 Aug 2005 22:46:01 +0000
parents
children 3c536224f0d0
comparison
equal deleted inserted replaced
11359:9480e0d0f563 11360:cf15c1cdcfbd
1 /* $Id: common.c 13582 2005-08-28 22:46:01Z boler $ */
2
3 /*
4 * (C) Copyright 2001-2002 Wojtek Kaniewski <wojtekka@irc.pl>
5 * Robert J. Woźny <speedy@ziew.org>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License Version
9 * 2.1 as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
19 * USA.
20 */
21
22 #include <sys/types.h>
23 #include <sys/ioctl.h>
24 #include <sys/socket.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
27 #ifdef sun
28 # include <sys/filio.h>
29 #endif
30
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <netdb.h>
34 #include <stdarg.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <unistd.h>
39
40 #include "libgadu.h"
41
42 FILE *gg_debug_file = NULL;
43
44 #ifndef GG_DEBUG_DISABLE
45
46 /*
47 * gg_debug() // funkcja wewnętrzna
48 *
49 * wyświetla komunikat o danym poziomie, o ile użytkownik sobie tego życzy.
50 *
51 * - level - poziom wiadomości
52 * - format... - treść wiadomości (kompatybilna z printf())
53 */
54 void gg_debug(int level, const char *format, ...)
55 {
56 va_list ap;
57 int old_errno = errno;
58
59 if (gg_debug_handler) {
60 va_start(ap, format);
61 (*gg_debug_handler)(level, format, ap);
62 va_end(ap);
63
64 goto cleanup;
65 }
66
67 if ((gg_debug_level & level)) {
68 va_start(ap, format);
69 vfprintf((gg_debug_file) ? gg_debug_file : stderr, format, ap);
70 va_end(ap);
71 }
72
73 cleanup:
74 errno = old_errno;
75 }
76
77 #endif
78
79 /*
80 * gg_vsaprintf() // funkcja pomocnicza
81 *
82 * robi dokładnie to samo, co vsprintf(), tyle że alokuje sobie wcześniej
83 * miejsce na dane. powinno działać na tych maszynach, które mają funkcję
84 * vsnprintf() zgodną z C99, jak i na wcześniejszych.
85 *
86 * - format - opis wyświetlanego tekstu jak dla printf()
87 * - ap - lista argumentów dla printf()
88 *
89 * zaalokowany bufor, który należy później zwolnić, lub NULL
90 * jeśli nie udało się wykonać zadania.
91 */
92 char *gg_vsaprintf(const char *format, va_list ap)
93 {
94 int size = 0;
95 const char *start;
96 char *buf = NULL;
97
98 #ifdef __GG_LIBGADU_HAVE_VA_COPY
99 va_list aq;
100
101 va_copy(aq, ap);
102 #else
103 # ifdef __GG_LIBGADU_HAVE___VA_COPY
104 va_list aq;
105
106 __va_copy(aq, ap);
107 # endif
108 #endif
109
110 start = format;
111
112 #ifndef __GG_LIBGADU_HAVE_C99_VSNPRINTF
113 {
114 int res;
115 char *tmp;
116
117 size = 128;
118 do {
119 size *= 2;
120 if (!(tmp = realloc(buf, size))) {
121 free(buf);
122 return NULL;
123 }
124 buf = tmp;
125 res = vsnprintf(buf, size, format, ap);
126 } while (res == size - 1 || res == -1);
127 }
128 #else
129 {
130 char tmp[2];
131
132 /* libce Solarisa przy buforze NULL zawsze zwracają -1, więc
133 * musimy podać coś istniejącego jako cel printf()owania. */
134 size = vsnprintf(tmp, sizeof(tmp), format, ap);
135 if (!(buf = malloc(size + 1)))
136 return NULL;
137 }
138 #endif
139
140 format = start;
141
142 #ifdef __GG_LIBGADU_HAVE_VA_COPY
143 vsnprintf(buf, size + 1, format, aq);
144 va_end(aq);
145 #else
146 # ifdef __GG_LIBGADU_HAVE___VA_COPY
147 vsnprintf(buf, size + 1, format, aq);
148 va_end(aq);
149 # else
150 vsnprintf(buf, size + 1, format, ap);
151 # endif
152 #endif
153
154 return buf;
155 }
156
157 /*
158 * gg_saprintf() // funkcja pomocnicza
159 *
160 * robi dokładnie to samo, co sprintf(), tyle że alokuje sobie wcześniej
161 * miejsce na dane. powinno działać na tych maszynach, które mają funkcję
162 * vsnprintf() zgodną z C99, jak i na wcześniejszych.
163 *
164 * - format... - treść taka sama jak w funkcji printf()
165 *
166 * zaalokowany bufor, który należy później zwolnić, lub NULL
167 * jeśli nie udało się wykonać zadania.
168 */
169 char *gg_saprintf(const char *format, ...)
170 {
171 va_list ap;
172 char *res;
173
174 va_start(ap, format);
175 res = gg_vsaprintf(format, ap);
176 va_end(ap);
177
178 return res;
179 }
180
181 /*
182 * gg_get_line() // funkcja pomocnicza
183 *
184 * podaje kolejną linię z bufora tekstowego. niszczy go bezpowrotnie, dzieląc
185 * na kolejne stringi. zdarza się, nie ma potrzeby pisania funkcji dublującej
186 * bufor żeby tylko mieć nieruszone dane wejściowe, skoro i tak nie będą nam
187 * poźniej potrzebne. obcina `\r\n'.
188 *
189 * - ptr - wskaźnik do zmiennej, która przechowuje aktualną pozycję
190 * w przemiatanym buforze
191 *
192 * wskaźnik do kolejnej linii tekstu lub NULL, jeśli to już koniec bufora.
193 */
194 char *gg_get_line(char **ptr)
195 {
196 char *foo, *res;
197
198 if (!ptr || !*ptr || !strcmp(*ptr, ""))
199 return NULL;
200
201 res = *ptr;
202
203 if (!(foo = strchr(*ptr, '\n')))
204 *ptr += strlen(*ptr);
205 else {
206 *ptr = foo + 1;
207 *foo = 0;
208 if (strlen(res) > 1 && res[strlen(res) - 1] == '\r')
209 res[strlen(res) - 1] = 0;
210 }
211
212 return res;
213 }
214
215 /*
216 * gg_connect() // funkcja pomocnicza
217 *
218 * łączy się z serwerem. pierwszy argument jest typu (void *), żeby nie
219 * musieć niczego inkludować w libgadu.h i nie psuć jakiś głupich zależności
220 * na dziwnych systemach.
221 *
222 * - addr - adres serwera (struct in_addr *)
223 * - port - port serwera
224 * - async - asynchroniczne połączenie
225 *
226 * deskryptor gniazda lub -1 w przypadku błędu (kod błędu w zmiennej errno).
227 */
228 int gg_connect(void *addr, int port, int async)
229 {
230 int sock, one = 1, errno2;
231 struct sockaddr_in sin;
232 struct in_addr *a = addr;
233 struct sockaddr_in myaddr;
234
235 gg_debug(GG_DEBUG_FUNCTION, "** gg_connect(%s, %d, %d);\n", inet_ntoa(*a), port, async);
236
237 if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
238 gg_debug(GG_DEBUG_MISC, "// gg_connect() socket() failed (errno=%d, %s)\n", errno, strerror(errno));
239 return -1;
240 }
241
242 memset(&myaddr, 0, sizeof(myaddr));
243 myaddr.sin_family = AF_INET;
244
245 myaddr.sin_addr.s_addr = gg_local_ip;
246
247 if (bind(sock, (struct sockaddr *) &myaddr, sizeof(myaddr)) == -1) {
248 gg_debug(GG_DEBUG_MISC, "// gg_connect() bind() failed (errno=%d, %s)\n", errno, strerror(errno));
249 return -1;
250 }
251
252 #ifdef ASSIGN_SOCKETS_TO_THREADS
253 gg_win32_thread_socket(0, sock);
254 #endif
255
256 if (async) {
257 #ifdef FIONBIO
258 if (ioctl(sock, FIONBIO, &one) == -1) {
259 #else
260 if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) {
261 #endif
262 gg_debug(GG_DEBUG_MISC, "// gg_connect() ioctl() failed (errno=%d, %s)\n", errno, strerror(errno));
263 errno2 = errno;
264 close(sock);
265 errno = errno2;
266 return -1;
267 }
268 }
269
270 sin.sin_port = htons(port);
271 sin.sin_family = AF_INET;
272 sin.sin_addr.s_addr = a->s_addr;
273
274 if (connect(sock, (struct sockaddr*) &sin, sizeof(sin)) == -1) {
275 if (errno && (!async || errno != EINPROGRESS)) {
276 gg_debug(GG_DEBUG_MISC, "// gg_connect() connect() failed (errno=%d, %s)\n", errno, strerror(errno));
277 errno2 = errno;
278 close(sock);
279 errno = errno2;
280 return -1;
281 }
282 gg_debug(GG_DEBUG_MISC, "// gg_connect() connect() in progress\n");
283 }
284
285 return sock;
286 }
287
288 /*
289 * gg_read_line() // funkcja pomocnicza
290 *
291 * czyta jedną linię tekstu z gniazda.
292 *
293 * - sock - deskryptor gniazda
294 * - buf - wskaźnik do bufora
295 * - length - długość bufora
296 *
297 * jeśli trafi na błąd odczytu lub podano nieprawidłowe parametry, zwraca NULL.
298 * inaczej zwraca buf.
299 */
300 char *gg_read_line(int sock, char *buf, int length)
301 {
302 int ret;
303
304 if (!buf || length < 0)
305 return NULL;
306
307 for (; length > 1; buf++, length--) {
308 do {
309 if ((ret = read(sock, buf, 1)) == -1 && errno != EINTR) {
310 gg_debug(GG_DEBUG_MISC, "// gg_read_line() error on read (errno=%d, %s)\n", errno, strerror(errno));
311 *buf = 0;
312 return NULL;
313 } else if (ret == 0) {
314 gg_debug(GG_DEBUG_MISC, "// gg_read_line() eof reached\n");
315 *buf = 0;
316 return NULL;
317 }
318 } while (ret == -1 && errno == EINTR);
319
320 if (*buf == '\n') {
321 buf++;
322 break;
323 }
324 }
325
326 *buf = 0;
327 return buf;
328 }
329
330 /*
331 * gg_chomp() // funkcja pomocnicza
332 *
333 * ucina "\r\n" lub "\n" z końca linii.
334 *
335 * - line - linia do przycięcia
336 */
337 void gg_chomp(char *line)
338 {
339 int len;
340
341 if (!line)
342 return;
343
344 len = strlen(line);
345
346 if (len > 0 && line[len - 1] == '\n')
347 line[--len] = 0;
348 if (len > 0 && line[len - 1] == '\r')
349 line[--len] = 0;
350 }
351
352 /*
353 * gg_urlencode() // funkcja wewnętrzna
354 *
355 * zamienia podany tekst na ciąg znaków do formularza http. przydaje się
356 * przy różnych usługach katalogu publicznego.
357 *
358 * - str - ciąg znaków do zakodowania
359 *
360 * zaalokowany bufor, który należy później zwolnić albo NULL
361 * w przypadku błędu.
362 */
363 char *gg_urlencode(const char *str)
364 {
365 char *q, *buf, hex[] = "0123456789abcdef";
366 const char *p;
367 unsigned int size = 0;
368
369 if (!str)
370 str = "";
371
372 for (p = str; *p; p++, size++) {
373 if (!((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || (*p >= '0' && *p <= '9') || *p == ' ') || (*p == '@') || (*p == '.') || (*p == '-'))
374 size += 2;
375 }
376
377 if (!(buf = malloc(size + 1)))
378 return NULL;
379
380 for (p = str, q = buf; *p; p++, q++) {
381 if ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || (*p >= '0' && *p <= '9') || (*p == '@') || (*p == '.') || (*p == '-'))
382 *q = *p;
383 else {
384 if (*p == ' ')
385 *q = '+';
386 else {
387 *q++ = '%';
388 *q++ = hex[*p >> 4 & 15];
389 *q = hex[*p & 15];
390 }
391 }
392 }
393
394 *q = 0;
395
396 return buf;
397 }
398
399 /*
400 * gg_http_hash() // funkcja wewnętrzna
401 *
402 * funkcja licząca hash dla adresu e-mail, hasła i paru innych.
403 *
404 * - format... - format kolejnych parametrów ('s' jeśli dany parametr jest
405 * ciągiem znaków lub 'u' jeśli numerem GG)
406 *
407 * hash wykorzystywany przy rejestracji i wszelkich manipulacjach własnego
408 * wpisu w katalogu publicznym.
409 */
410 int gg_http_hash(const char *format, ...)
411 {
412 unsigned int a, c, i, j;
413 va_list ap;
414 int b = -1;
415
416 va_start(ap, format);
417
418 for (j = 0; j < strlen(format); j++) {
419 char *arg, buf[16];
420
421 if (format[j] == 'u') {
422 snprintf(buf, sizeof(buf), "%d", va_arg(ap, uin_t));
423 arg = buf;
424 } else {
425 if (!(arg = va_arg(ap, char*)))
426 arg = "";
427 }
428
429 i = 0;
430 while ((c = (unsigned char) arg[i++]) != 0) {
431 a = (c ^ b) + (c << 8);
432 b = (a >> 24) | (a << 8);
433 }
434 }
435
436 va_end(ap);
437
438 return (b < 0 ? -b : b);
439 }
440
441 /*
442 * gg_gethostbyname() // funkcja pomocnicza
443 *
444 * odpowiednik gethostbyname() troszczący się o współbieżność, gdy mamy do
445 * dyspozycji funkcję gethostbyname_r().
446 *
447 * - hostname - nazwa serwera
448 *
449 * zwraca wskaźnik na strukturę in_addr, którą należy zwolnić.
450 */
451 struct in_addr *gg_gethostbyname(const char *hostname)
452 {
453 struct in_addr *addr = NULL;
454
455 #ifdef HAVE_GETHOSTBYNAME_R
456 char *tmpbuf = NULL, *buf = NULL;
457 struct hostent *hp = NULL, *hp2 = NULL;
458 int h_errnop, ret;
459 size_t buflen = 1024;
460 int new_errno;
461
462 new_errno = ENOMEM;
463
464 if (!(addr = malloc(sizeof(struct in_addr))))
465 goto cleanup;
466
467 if (!(hp = calloc(1, sizeof(*hp))))
468 goto cleanup;
469
470 if (!(buf = malloc(buflen)))
471 goto cleanup;
472
473 tmpbuf = buf;
474
475 while ((ret = gethostbyname_r(hostname, hp, buf, buflen, &hp2, &h_errnop)) == ERANGE) {
476 buflen *= 2;
477
478 if (!(tmpbuf = realloc(buf, buflen)))
479 break;
480
481 buf = tmpbuf;
482 }
483
484 if (ret)
485 new_errno = h_errnop;
486
487 if (ret || !hp2 || !tmpbuf)
488 goto cleanup;
489
490 memcpy(addr, hp->h_addr, sizeof(struct in_addr));
491
492 free(buf);
493 free(hp);
494
495 return addr;
496
497 cleanup:
498 errno = new_errno;
499
500 if (addr)
501 free(addr);
502 if (hp)
503 free(hp);
504 if (buf)
505 free(buf);
506
507 return NULL;
508 #else
509 struct hostent *hp;
510
511 if (!(addr = malloc(sizeof(struct in_addr)))) {
512 goto cleanup;
513 }
514
515 if (!(hp = gethostbyname(hostname)))
516 goto cleanup;
517
518 memcpy(addr, hp->h_addr, sizeof(struct in_addr));
519
520 return addr;
521
522 cleanup:
523 if (addr)
524 free(addr);
525
526 return NULL;
527 #endif
528 }
529
530 #ifdef ASSIGN_SOCKETS_TO_THREADS
531
532 typedef struct gg_win32_thread {
533 int id;
534 int socket;
535 struct gg_win32_thread *next;
536 } gg_win32_thread;
537
538 struct gg_win32_thread *gg_win32_threads = 0;
539
540 /*
541 * gg_win32_thread_socket() // funkcja pomocnicza, tylko dla win32
542 *
543 * zwraca deskryptor gniazda, które było ostatnio tworzone dla wątku
544 * o podanym identyfikatorze.
545 *
546 * jeśli na win32 przy połączeniach synchronicznych zapamiętamy w jakim
547 * wątku uruchomiliśmy funkcję, która się z czymkolwiek łączy, to z osobnego
548 * wątku możemy anulować połączenie poprzez gg_win32_thread_socket(watek, -1);
549 *
550 * - thread_id - id wątku. jeśli jest równe 0, brany jest aktualny wątek,
551 * jeśli równe -1, usuwa wpis o podanym sockecie.
552 * - socket - deskryptor gniazda. jeśli równe 0, zwraca deskryptor gniazda
553 * dla podanego wątku, jeśli równe -1, usuwa wpis, jeśli coś
554 * innego, ustawia dla podanego wątku dany numer deskryptora.
555 *
556 * jeśli socket jest równe 0, zwraca deskryptor gniazda dla podanego wątku.
557 */
558 int gg_win32_thread_socket(int thread_id, int socket)
559 {
560 char close = (thread_id == -1) || socket == -1;
561 gg_win32_thread *wsk = gg_win32_threads;
562 gg_win32_thread **p_wsk = &gg_win32_threads;
563
564 if (!thread_id)
565 thread_id = GetCurrentThreadId();
566
567 while (wsk) {
568 if ((thread_id == -1 && wsk->socket == socket) || wsk->id == thread_id) {
569 if (close) {
570 /* socket zostaje usuniety */
571 closesocket(wsk->socket);
572 *p_wsk = wsk->next;
573 free(wsk);
574 return 1;
575 } else if (!socket) {
576 /* socket zostaje zwrocony */
577 return wsk->socket;
578 } else {
579 /* socket zostaje ustawiony */
580 wsk->socket = socket;
581 return socket;
582 }
583 }
584 p_wsk = &(wsk->next);
585 wsk = wsk->next;
586 }
587
588 if (close && socket != -1)
589 closesocket(socket);
590 if (close || !socket)
591 return 0;
592
593 /* Dodaje nowy element */
594 wsk = malloc(sizeof(gg_win32_thread));
595 wsk->id = thread_id;
596 wsk->socket = socket;
597 wsk->next = 0;
598 *p_wsk = wsk;
599
600 return socket;
601 }
602
603 #endif /* ASSIGN_SOCKETS_TO_THREADS */
604
605 static char gg_base64_charset[] =
606 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
607
608 /*
609 * gg_base64_encode()
610 *
611 * zapisuje ciąg znaków w base64.
612 *
613 * - buf - ciąg znaków.
614 *
615 * zaalokowany bufor.
616 */
617 char *gg_base64_encode(const char *buf)
618 {
619 char *out, *res;
620 unsigned int i = 0, j = 0, k = 0, len = strlen(buf);
621
622 res = out = malloc((len / 3 + 1) * 4 + 2);
623
624 if (!res)
625 return NULL;
626
627 while (j <= len) {
628 switch (i % 4) {
629 case 0:
630 k = (buf[j] & 252) >> 2;
631 break;
632 case 1:
633 if (j < len)
634 k = ((buf[j] & 3) << 4) | ((buf[j + 1] & 240) >> 4);
635 else
636 k = (buf[j] & 3) << 4;
637
638 j++;
639 break;
640 case 2:
641 if (j < len)
642 k = ((buf[j] & 15) << 2) | ((buf[j + 1] & 192) >> 6);
643 else
644 k = (buf[j] & 15) << 2;
645
646 j++;
647 break;
648 case 3:
649 k = buf[j++] & 63;
650 break;
651 }
652 *out++ = gg_base64_charset[k];
653 i++;
654 }
655
656 if (i % 4)
657 for (j = 0; j < 4 - (i % 4); j++, out++)
658 *out = '=';
659
660 *out = 0;
661
662 return res;
663 }
664
665 /*
666 * gg_base64_decode()
667 *
668 * dekoduje ciąg znaków z base64.
669 *
670 * - buf - ciąg znaków.
671 *
672 * zaalokowany bufor.
673 */
674 char *gg_base64_decode(const char *buf)
675 {
676 char *res, *save, *foo, val;
677 const char *end;
678 unsigned int index = 0;
679
680 if (!buf)
681 return NULL;
682
683 save = res = calloc(1, (strlen(buf) / 4 + 1) * 3 + 2);
684
685 if (!save)
686 return NULL;
687
688 end = buf + strlen(buf);
689
690 while (*buf && buf < end) {
691 if (*buf == '\r' || *buf == '\n') {
692 buf++;
693 continue;
694 }
695 if (!(foo = strchr(gg_base64_charset, *buf)))
696 foo = gg_base64_charset;
697 val = (int)(foo - gg_base64_charset);
698 buf++;
699 switch (index) {
700 case 0:
701 *res |= val << 2;
702 break;
703 case 1:
704 *res++ |= val >> 4;
705 *res |= val << 4;
706 break;
707 case 2:
708 *res++ |= val >> 2;
709 *res |= val << 6;
710 break;
711 case 3:
712 *res++ |= val;
713 break;
714 }
715 index++;
716 index %= 4;
717 }
718 *res = 0;
719
720 return save;
721 }
722
723 /*
724 * gg_proxy_auth() // funkcja wewnętrzna
725 *
726 * tworzy nagłówek autoryzacji dla proxy.
727 *
728 * zaalokowany tekst lub NULL, jeśli proxy nie jest włączone lub nie wymaga
729 * autoryzacji.
730 */
731 char *gg_proxy_auth()
732 {
733 char *tmp, *enc, *out;
734 unsigned int tmp_size;
735
736 if (!gg_proxy_enabled || !gg_proxy_username || !gg_proxy_password)
737 return NULL;
738
739 if (!(tmp = malloc((tmp_size = strlen(gg_proxy_username) + strlen(gg_proxy_password) + 2))))
740 return NULL;
741
742 snprintf(tmp, tmp_size, "%s:%s", gg_proxy_username, gg_proxy_password);
743
744 if (!(enc = gg_base64_encode(tmp))) {
745 free(tmp);
746 return NULL;
747 }
748
749 free(tmp);
750
751 if (!(out = malloc(strlen(enc) + 40))) {
752 free(enc);
753 return NULL;
754 }
755
756 snprintf(out, strlen(enc) + 40, "Proxy-Authorization: Basic %s\r\n", enc);
757
758 free(enc);
759
760 return out;
761 }
762
763 static uint32_t gg_crc32_table[256];
764 static int gg_crc32_initialized = 0;
765
766 /*
767 * gg_crc32_make_table() // funkcja wewnętrzna
768 */
769 static void gg_crc32_make_table()
770 {
771 uint32_t h = 1;
772 unsigned int i, j;
773
774 memset(gg_crc32_table, 0, sizeof(gg_crc32_table));
775
776 for (i = 128; i; i >>= 1) {
777 h = (h >> 1) ^ ((h & 1) ? 0xedb88320L : 0);
778
779 for (j = 0; j < 256; j += 2 * i)
780 gg_crc32_table[i + j] = gg_crc32_table[j] ^ h;
781 }
782
783 gg_crc32_initialized = 1;
784 }
785
786 /*
787 * gg_crc32()
788 *
789 * wyznacza sumę kontrolną CRC32 danego bloku danych.
790 *
791 * - crc - suma kontrola poprzedniego bloku danych lub 0 jeśli pierwszy
792 * - buf - bufor danych
793 * - size - ilość danych
794 *
795 * suma kontrolna CRC32.
796 */
797 uint32_t gg_crc32(uint32_t crc, const unsigned char *buf, int len)
798 {
799 if (!gg_crc32_initialized)
800 gg_crc32_make_table();
801
802 if (!buf || len < 0)
803 return crc;
804
805 crc ^= 0xffffffffL;
806
807 while (len--)
808 crc = (crc >> 8) ^ gg_crc32_table[(crc ^ *buf++) & 0xff];
809
810 return crc ^ 0xffffffffL;
811 }
812
813
814 /*
815 * Local variables:
816 * c-indentation-style: k&r
817 * c-basic-offset: 8
818 * indent-tabs-mode: notnil
819 * End:
820 *
821 * vim: shiftwidth=8:
822 */