libgaim/protocols/gg/lib/common.c

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

mercurial