comparison arib25v021/arib25/src/ts_section_parser.c @ 0:67e8eca28a80

initial import
author Yoshiki Yazawa <yaz@honeyplanet.jp>
date Mon, 16 Feb 2009 15:41:49 +0900
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:67e8eca28a80
1 #include <stdlib.h>
2 #include <string.h>
3
4 #include "ts_section_parser.h"
5 #include "ts_section_parser_error_code.h"
6
7 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
8 inner structures
9 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
10 typedef struct {
11 void *prev;
12 void *next;
13 TS_SECTION sect;
14 int32_t ref;
15 } TS_SECTION_ELEM;
16
17 typedef struct {
18 TS_SECTION_ELEM *head;
19 TS_SECTION_ELEM *tail;
20 int32_t count;
21 } TS_SECTION_LIST;
22
23 typedef struct {
24
25 int32_t pid;
26
27 TS_SECTION_ELEM *work;
28 TS_SECTION_ELEM *last;
29
30 TS_SECTION_LIST pool;
31 TS_SECTION_LIST buff;
32
33 TS_SECTION_PARSER_STAT stat;
34
35 } TS_SECTION_PARSER_PRIVATE_DATA;
36
37 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
38 constant values
39 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
40 #define MAX_RAW_SECTION_SIZE 4100
41
42 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
43 function prottypes (interface method)
44 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
45 static void release_ts_section_parser(void *parser);
46 static int reset_ts_section_parser(void *parser);
47 static int put_ts_section_parser(void *parser, TS_HEADER *hdr, uint8_t *data, int size);
48 static int get_ts_section_parser(void *parser, TS_SECTION *sect);
49 static int ret_ts_section_parser(void *parser, TS_SECTION *sect);
50 static int get_count_ts_section_parser(void *parser);
51 static int get_stat_ts_section_parser(void *parser, TS_SECTION_PARSER_STAT *stat);
52
53 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
54 global function implementation (factory method)
55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
56 TS_SECTION_PARSER *create_ts_section_parser()
57 {
58 TS_SECTION_PARSER *r;
59 TS_SECTION_PARSER_PRIVATE_DATA *prv;
60
61 int n;
62
63 n = sizeof(TS_SECTION_PARSER_PRIVATE_DATA);
64 n += sizeof(TS_SECTION_PARSER);
65
66 prv = (TS_SECTION_PARSER_PRIVATE_DATA *)calloc(1, n);
67 if(prv == NULL){
68 /* failed on malloc() - no enough memory */
69 return NULL;
70 }
71
72 prv->pid = -1;
73
74 r = (TS_SECTION_PARSER *)(prv+1);
75 r->private_data = prv;
76
77 r->release = release_ts_section_parser;
78 r->reset = reset_ts_section_parser;
79
80 r->put = put_ts_section_parser;
81 r->get = get_ts_section_parser;
82 r->ret = ret_ts_section_parser;
83
84 r->get_count = get_count_ts_section_parser;
85
86 r->get_stat = get_stat_ts_section_parser;
87
88 return r;
89 }
90
91 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
92 function prottypes (private method)
93 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
94 static TS_SECTION_PARSER_PRIVATE_DATA *private_data(void *parser);
95 static void teardown(TS_SECTION_PARSER_PRIVATE_DATA *prv);
96
97 static int put_exclude_section_start(TS_SECTION_PARSER_PRIVATE_DATA *prv, uint8_t *data, int size);
98 static int put_include_section_start(TS_SECTION_PARSER_PRIVATE_DATA *prv, uint8_t *data, int size);
99
100 static void reset_section(TS_SECTION *sect);
101 static void append_section_data(TS_SECTION *sect, uint8_t *data, int size);
102 static int check_section_complete(TS_SECTION *sect);
103
104 static int compare_elem_section(TS_SECTION_ELEM *a, TS_SECTION_ELEM *b);
105
106 static void cancel_elem_empty(TS_SECTION_PARSER_PRIVATE_DATA *prv, TS_SECTION_ELEM *elem);
107 static void cancel_elem_error(TS_SECTION_PARSER_PRIVATE_DATA *prv, TS_SECTION_ELEM *elem);
108 static void cancel_elem_same(TS_SECTION_PARSER_PRIVATE_DATA *prv, TS_SECTION_ELEM *elem);
109 static void commit_elem_updated(TS_SECTION_PARSER_PRIVATE_DATA *prv, TS_SECTION_ELEM *elem);
110
111 static TS_SECTION_ELEM *query_work_elem(TS_SECTION_PARSER_PRIVATE_DATA *prv);
112
113 static void extract_ts_section_header(TS_SECTION *sect);
114
115 static TS_SECTION_ELEM *create_ts_section_elem();
116 static TS_SECTION_ELEM *get_ts_section_list_head(TS_SECTION_LIST *list);
117 static void put_ts_section_list_tail(TS_SECTION_LIST *list, TS_SECTION_ELEM *elem);
118 static void unlink_ts_section_list(TS_SECTION_LIST *list, TS_SECTION_ELEM *elem);
119 static void clear_ts_section_list(TS_SECTION_LIST *list);
120
121 static uint32_t crc32(uint8_t *head, uint8_t *tail);
122
123 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
124 function implementation (interface method)
125 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
126 static void release_ts_section_parser(void *parser)
127 {
128 TS_SECTION_PARSER_PRIVATE_DATA *prv;
129
130 prv = private_data(parser);
131 if(prv == NULL){
132 return;
133 }
134
135 teardown(prv);
136
137 memset(parser, 0, sizeof(TS_SECTION_PARSER));
138 free(prv);
139 }
140
141 static int reset_ts_section_parser(void *parser)
142 {
143 TS_SECTION_PARSER_PRIVATE_DATA *prv;
144
145 prv = private_data(parser);
146 if(prv == NULL){
147 return TS_SECTION_PARSER_ERROR_INVALID_PARAM;
148 }
149
150 teardown(prv);
151
152 return 0;
153 }
154
155 static int put_ts_section_parser(void *parser, TS_HEADER *hdr, uint8_t *data, int size)
156 {
157 TS_SECTION_PARSER_PRIVATE_DATA *prv;
158
159 prv = private_data(parser);
160 if( (prv == NULL) || (hdr == NULL) || (data == NULL) || (size < 1) ){
161 return TS_SECTION_PARSER_ERROR_INVALID_PARAM;
162 }
163
164 if( (prv->pid >= 0) && (prv->pid != hdr->pid) ){
165 return TS_SECTION_PARSER_ERROR_INVALID_TS_PID;
166 }
167
168 prv->pid = hdr->pid;
169
170 if(hdr->payload_unit_start_indicator == 0){
171 /* exclude section start */
172 return put_exclude_section_start(prv, data, size);
173 }else{
174 /* include section start */
175 return put_include_section_start(prv, data, size);
176 }
177 }
178
179 static int get_ts_section_parser(void *parser, TS_SECTION *sect)
180 {
181 TS_SECTION_PARSER_PRIVATE_DATA *prv;
182 TS_SECTION_ELEM *w;
183
184 prv = private_data(parser);
185 if( (prv == NULL) || (sect == NULL) ){
186 return TS_SECTION_PARSER_ERROR_INVALID_PARAM;
187 }
188
189 w = get_ts_section_list_head(&(prv->buff));
190 if(w == NULL){
191 memset(sect, 0, sizeof(TS_SECTION));
192 return TS_SECTION_PARSER_ERROR_NO_SECTION_DATA;
193 }
194
195 memcpy(sect, &(w->sect), sizeof(TS_SECTION));
196 put_ts_section_list_tail(&(prv->pool), w);
197
198 return 0;
199 }
200
201 static int ret_ts_section_parser(void *parser, TS_SECTION *sect)
202 {
203 TS_SECTION_PARSER_PRIVATE_DATA *prv;
204 TS_SECTION_ELEM *w;
205
206 prv = private_data(parser);
207 if( (prv == NULL) || (sect == NULL) ){
208 return TS_SECTION_PARSER_ERROR_INVALID_PARAM;
209 }
210
211 w = prv->pool.tail;
212 while(w != NULL){
213 if(w->sect.data == sect->data){
214 break;
215 }
216 w = (TS_SECTION_ELEM *)(w->prev);
217 }
218
219 if( (w != NULL) && (w->ref > 0) ){
220 w->ref -= 1;
221 }
222
223 return 0;
224 }
225
226 static int get_count_ts_section_parser(void *parser)
227 {
228 TS_SECTION_PARSER_PRIVATE_DATA *prv;
229
230 prv = private_data(parser);
231 if(prv == NULL){
232 return TS_SECTION_PARSER_ERROR_INVALID_PARAM;
233 }
234
235 return prv->buff.count;
236 }
237
238 static int get_stat_ts_section_parser(void *parser, TS_SECTION_PARSER_STAT *stat)
239 {
240 TS_SECTION_PARSER_PRIVATE_DATA *prv;
241
242 prv = private_data(parser);
243 if( (prv == NULL) || (stat == NULL) ){
244 return TS_SECTION_PARSER_ERROR_INVALID_PARAM;
245 }
246
247 memcpy(stat, &(prv->stat), sizeof(TS_SECTION_PARSER_STAT));
248
249 return 0;
250 }
251
252 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
253 function implementation (private method)
254 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
255 static TS_SECTION_PARSER_PRIVATE_DATA *private_data(void *parser)
256 {
257 TS_SECTION_PARSER_PRIVATE_DATA *r;
258 TS_SECTION_PARSER *p;
259
260 p = (TS_SECTION_PARSER *)parser;
261 if(p == NULL){
262 return NULL;
263 }
264
265 r = (TS_SECTION_PARSER_PRIVATE_DATA *)(p->private_data);
266 if( ((void *)(r+1)) != parser ){
267 return NULL;
268 }
269
270 return r;
271 }
272
273 static void teardown(TS_SECTION_PARSER_PRIVATE_DATA *prv)
274 {
275 prv->pid = -1;
276
277 if(prv->work != NULL){
278 free(prv->work);
279 prv->work = NULL;
280 }
281
282 prv->last = NULL;
283
284 clear_ts_section_list(&(prv->pool));
285 clear_ts_section_list(&(prv->buff));
286
287 memset(&(prv->stat), 0, sizeof(TS_SECTION_PARSER_STAT));
288 }
289
290 static int put_exclude_section_start(TS_SECTION_PARSER_PRIVATE_DATA *prv, uint8_t *data, int size)
291 {
292 TS_SECTION_ELEM *w;
293
294 w = prv->work;
295 if( (w == NULL) || (w->sect.raw == w->sect.tail) ){
296 /* no previous data */
297 return 0;
298 }
299
300 append_section_data(&(w->sect), data, size);
301 if(check_section_complete(&(w->sect)) == 0){
302 /* need more data */
303 return 0;
304 }
305
306 prv->work = NULL;
307
308 if( (w->sect.hdr.section_syntax_indicator != 0) &&
309 (crc32(w->sect.raw, w->sect.tail) != 0) ){
310 cancel_elem_error(prv, w);
311 return TS_SECTION_PARSER_WARN_CRC_MISSMATCH;
312 }
313
314 if(compare_elem_section(w, prv->last) == 0){
315 /* same section data */
316 cancel_elem_same(prv, w);
317 return 0;
318 }
319
320 commit_elem_updated(prv, w);
321 return 0;
322 }
323
324 static int put_include_section_start(TS_SECTION_PARSER_PRIVATE_DATA *prv, uint8_t *data, int size)
325 {
326 TS_SECTION_ELEM *w;
327
328 int pointer_field;
329
330 uint8_t *p;
331 uint8_t *tail;
332
333 int r;
334 int length;
335
336 p = data;
337 tail = p + size;
338
339 r = 0;
340
341 pointer_field = p[0];
342 p += 1;
343
344 if( (p+pointer_field) >= tail ){
345 /* input data is probably broken */
346 w = prv->work;
347 prv->work = NULL;
348 if(w != NULL) {
349 if(w->sect.raw != w->sect.tail){
350 cancel_elem_error(prv, w);
351 return TS_SECTION_PARSER_WARN_LENGTH_MISSMATCH;
352 }
353 cancel_elem_empty(prv, w);
354 }
355 return 0;
356 }
357
358 if(pointer_field > 0){
359 r = put_exclude_section_start(prv, p, pointer_field);
360 if(r < 0){
361 return r;
362 }
363 p += pointer_field;
364 }
365
366 w = prv->work;
367 prv->work = NULL;
368
369 if(w != NULL){
370 if(w->sect.raw != w->sect.tail){
371 cancel_elem_error(prv, w);
372 r = TS_SECTION_PARSER_WARN_LENGTH_MISSMATCH;
373 }else{
374 cancel_elem_empty(prv, w);
375 }
376 w = NULL;
377 }
378
379 do {
380
381 w = query_work_elem(prv);
382 if(w == NULL){
383 return TS_SECTION_PARSER_ERROR_NO_ENOUGH_MEMORY;
384 }
385
386 append_section_data(&(w->sect), p, tail-p);
387 if(check_section_complete(&(w->sect)) == 0){
388 /* need more data */
389 prv->work = w;
390 return 0;
391 }
392 length = (w->sect.tail - w->sect.raw);
393
394 if( (w->sect.hdr.section_syntax_indicator != 0) &&
395 (crc32(w->sect.raw, w->sect.tail) != 0) ){
396 cancel_elem_error(prv, w);
397 r = TS_SECTION_PARSER_WARN_CRC_MISSMATCH;
398 }else if(compare_elem_section(w, prv->last) == 0){
399 cancel_elem_same(prv, w);
400 }else{
401 commit_elem_updated(prv, w);
402 }
403
404 p += length;
405
406 } while ( (p < tail) && (p[0] != 0xff) );
407
408 return r;
409 }
410
411 static void reset_section(TS_SECTION *sect)
412 {
413 memset(&(sect->hdr), 0, sizeof(TS_SECTION_HEADER));
414 sect->tail = sect->raw;
415 sect->data = NULL;
416 }
417
418 static void append_section_data(TS_SECTION *sect, uint8_t *data, int size)
419 {
420 int m,n;
421
422 m = sect->tail - sect->raw;
423 n = MAX_RAW_SECTION_SIZE - m;
424
425 if(size < n){
426 n = size;
427 }
428 memcpy(sect->tail, data, n);
429 sect->tail += n;
430 m += n;
431
432 if(sect->data == NULL){
433 extract_ts_section_header(sect);
434 }
435
436 if(sect->data == NULL){
437 /* need more data */
438 return;
439 }
440
441 n = sect->hdr.section_length + 3;
442 if(m > n){
443 sect->tail = sect->raw + n;
444 }
445
446 return;
447 }
448
449 static int check_section_complete(TS_SECTION *sect)
450 {
451 int m,n;
452
453 if(sect->data == NULL){
454 return 0;
455 }
456
457 m = sect->tail - sect->raw;
458 n = sect->hdr.section_length + 3;
459
460 if(n > m){
461 return 0;
462 }
463
464 return 1;
465 }
466
467 static int compare_elem_section(TS_SECTION_ELEM *a, TS_SECTION_ELEM *b)
468 {
469 int m,n;
470
471 if( (a == NULL) || (b == NULL) ){
472 return 1;
473 }
474
475 m = a->sect.tail - a->sect.raw;
476 n = b->sect.tail - b->sect.raw;
477 if( m != n ){
478 return 1;
479 }
480
481 if(memcmp(a->sect.raw, b->sect.raw, m) != 0){
482 return 1;
483 }
484
485 return 0;
486 }
487
488 static void cancel_elem_empty(TS_SECTION_PARSER_PRIVATE_DATA *prv, TS_SECTION_ELEM *elem)
489 {
490 reset_section(&(elem->sect));
491 elem->ref = 0;
492 put_ts_section_list_tail(&(prv->pool), elem);
493 }
494
495 static void cancel_elem_error(TS_SECTION_PARSER_PRIVATE_DATA *prv, TS_SECTION_ELEM *elem)
496 {
497 reset_section(&(elem->sect));
498 elem->ref = 0;
499 put_ts_section_list_tail(&(prv->pool), elem);
500 prv->stat.total += 1;
501 prv->stat.error += 1;
502 }
503
504 static void cancel_elem_same(TS_SECTION_PARSER_PRIVATE_DATA *prv, TS_SECTION_ELEM *elem)
505 {
506 reset_section(&(elem->sect));
507 elem->ref = 0;
508 put_ts_section_list_tail(&(prv->pool), elem);
509 prv->stat.total +=1;
510 }
511
512 static void commit_elem_updated(TS_SECTION_PARSER_PRIVATE_DATA *prv, TS_SECTION_ELEM *elem)
513 {
514 if( (prv->last != NULL) && (prv->last->ref > 0) ){
515 prv->last->ref -= 1;
516 }
517
518 elem->ref = 2;
519 prv->last = elem;
520 put_ts_section_list_tail(&(prv->buff), elem);
521 prv->stat.total += 1;
522 prv->stat.unique += 1;
523 }
524
525 static TS_SECTION_ELEM *query_work_elem(TS_SECTION_PARSER_PRIVATE_DATA *prv)
526 {
527 TS_SECTION_ELEM *r;
528
529 r = prv->pool.head;
530 while(r != NULL){
531 if(r->ref < 1){
532 break;
533 }
534 r = (TS_SECTION_ELEM *)(r->next);
535 }
536
537 if(r != NULL){
538 unlink_ts_section_list(&(prv->pool), r);
539 reset_section(&(r->sect));
540 r->ref = 0;
541 return r;
542 }
543
544 return create_ts_section_elem();
545 }
546
547 static void extract_ts_section_header(TS_SECTION *sect)
548 {
549 int size;
550 uint8_t *p;
551
552 sect->data = NULL;
553
554 size = sect->tail - sect->raw;
555 if(size < 3){
556 /* need more data */
557 return;
558 }
559
560 p = sect->raw;
561
562 sect->hdr.table_id = p[0];
563 sect->hdr.section_syntax_indicator = (p[1] >> 7) & 0x01;
564 sect->hdr.private_indicator = (p[1] >> 6) & 0x01;
565 sect->hdr.section_length =((p[1] << 8) | p[2]) & 0x0fff;
566
567 if(sect->hdr.section_syntax_indicator == 0){
568 /* short format section header */
569 sect->data = p+3;
570 return;
571 }
572
573 /* long format section header */
574
575 if(size < 8){
576 /* need more data */
577 return;
578 }
579
580 sect->hdr.table_id_extension =((p[3] << 8) | p[4]);
581 sect->hdr.version_number = (p[5] >> 1) & 0x1f;
582 sect->hdr.current_next_indicator = p[5] & 0x01;
583 sect->hdr.section_number = p[6];
584 sect->hdr.last_section_number = p[7];
585
586 sect->data = p+8;
587
588 return;
589 }
590
591 static TS_SECTION_ELEM *create_ts_section_elem()
592 {
593 TS_SECTION_ELEM *r;
594 int n;
595
596 n = sizeof(TS_SECTION_ELEM) + MAX_RAW_SECTION_SIZE;
597 r = (TS_SECTION_ELEM *)calloc(1, n);
598 if(r == NULL){
599 /* failed on malloc() */
600 return NULL;
601 }
602
603 r->sect.raw = (uint8_t *)(r+1);
604 r->sect.tail = r->sect.raw;
605
606 return r;
607 }
608
609 static TS_SECTION_ELEM *get_ts_section_list_head(TS_SECTION_LIST *list)
610 {
611 TS_SECTION_ELEM *r;
612
613 if(list == NULL){/* invalid param */
614 return NULL;
615 }
616
617 r = list->head;
618 if(r == NULL){
619 return NULL;
620 }
621
622 list->head = (TS_SECTION_ELEM *)(r->next);
623 if(list->head != NULL){
624 list->head->prev = NULL;
625 list->count -= 1;
626 }else{
627 list->tail = NULL;
628 list->count = 0;
629 }
630
631 r->next = NULL;
632
633 return r;
634 }
635
636 static void put_ts_section_list_tail(TS_SECTION_LIST *list, TS_SECTION_ELEM *elem)
637 {
638 if( (list == NULL) || (elem == NULL) ){
639 /* invalid param */
640 return;
641 }
642
643 if(list->tail != NULL){
644 elem->prev = list->tail;
645 elem->next = NULL;
646 list->tail->next = elem;
647 list->tail = elem;
648 list->count += 1;
649 }else{
650 elem->prev = NULL;
651 elem->next = NULL;
652 list->head = elem;
653 list->tail = elem;
654 list->count = 1;
655 }
656 }
657
658 static void unlink_ts_section_list(TS_SECTION_LIST *list, TS_SECTION_ELEM *elem)
659 {
660 TS_SECTION_ELEM *prev;
661 TS_SECTION_ELEM *next;
662
663 if( (list == NULL) || (elem == NULL) ){
664 /* invalid param */
665 return;
666 }
667
668 prev = (TS_SECTION_ELEM *)(elem->prev);
669 next = (TS_SECTION_ELEM *)(elem->next);
670
671 if(prev != NULL){
672 prev->next = next;
673 }else{
674 list->head = next;
675 }
676 if(next != NULL){
677 next->prev = prev;
678 }else{
679 list->tail = prev;
680 }
681 list->count -= 1;
682 }
683
684 static void clear_ts_section_list(TS_SECTION_LIST *list)
685 {
686 TS_SECTION_ELEM *e;
687 TS_SECTION_ELEM *n;
688
689 if(list == NULL){ /* invalid param */
690 return;
691 }
692
693 e = list->head;
694 while(e != NULL){
695 n = (TS_SECTION_ELEM *)(e->next);
696 free(e);
697 e = n;
698 }
699
700 list->head = NULL;
701 list->tail = NULL;
702 list->count = 0;
703 }
704
705 static uint32_t crc32(uint8_t *head, uint8_t *tail)
706 {
707 uint32_t crc;
708 uint8_t *p;
709
710 static const uint32_t table[256] = {
711 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9,
712 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005,
713 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61,
714 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD,
715
716 0x4C11DB70, 0x48D0C6C7, 0x4593E01E, 0x4152FDA9,
717 0x5F15ADAC, 0x5BD4B01B, 0x569796C2, 0x52568B75,
718 0x6A1936C8, 0x6ED82B7F, 0x639B0DA6, 0x675A1011,
719 0x791D4014, 0x7DDC5DA3, 0x709F7B7A, 0x745E66CD,
720
721 0x9823B6E0, 0x9CE2AB57, 0x91A18D8E, 0x95609039,
722 0x8B27C03C, 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5,
723 0xBE2B5B58, 0xBAEA46EF, 0xB7A96036, 0xB3687D81,
724 0xAD2F2D84, 0xA9EE3033, 0xA4AD16EA, 0xA06C0B5D,
725
726 0xD4326D90, 0xD0F37027, 0xDDB056FE, 0xD9714B49,
727 0xC7361B4C, 0xC3F706FB, 0xCEB42022, 0xCA753D95,
728 0xF23A8028, 0xF6FB9D9F, 0xFBB8BB46, 0xFF79A6F1,
729 0xE13EF6F4, 0xE5FFEB43, 0xE8BCCD9A, 0xEC7DD02D,
730
731 0x34867077, 0x30476DC0, 0x3D044B19, 0x39C556AE,
732 0x278206AB, 0x23431B1C, 0x2E003DC5, 0x2AC12072,
733 0x128E9DCF, 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16,
734 0x018AEB13, 0x054BF6A4, 0x0808D07D, 0x0CC9CDCA,
735
736 0x7897AB07, 0x7C56B6B0, 0x71159069, 0x75D48DDE,
737 0x6B93DDDB, 0x6F52C06C, 0x6211E6B5, 0x66D0FB02,
738 0x5E9F46BF, 0x5A5E5B08, 0x571D7DD1, 0x53DC6066,
739 0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA,
740
741 0xACA5C697, 0xA864DB20, 0xA527FDF9, 0xA1E6E04E,
742 0xBFA1B04B, 0xBB60ADFC, 0xB6238B25, 0xB2E29692,
743 0x8AAD2B2F, 0x8E6C3698, 0x832F1041, 0x87EE0DF6,
744 0x99A95DF3, 0x9D684044, 0x902B669D, 0x94EA7B2A,
745
746 0xE0B41DE7, 0xE4750050, 0xE9362689, 0xEDF73B3E,
747 0xF3B06B3B, 0xF771768C, 0xFA325055, 0xFEF34DE2,
748 0xC6BCF05F, 0xC27DEDE8, 0xCF3ECB31, 0xCBFFD686,
749 0xD5B88683, 0xD1799B34, 0xDC3ABDED, 0xD8FBA05A,
750
751 0x690CE0EE, 0x6DCDFD59, 0x608EDB80, 0x644FC637,
752 0x7A089632, 0x7EC98B85, 0x738AAD5C, 0x774BB0EB,
753 0x4F040D56, 0x4BC510E1, 0x46863638, 0x42472B8F,
754 0x5C007B8A, 0x58C1663D, 0x558240E4, 0x51435D53,
755
756 0x251D3B9E, 0x21DC2629, 0x2C9F00F0, 0x285E1D47,
757 0x36194D42, 0x32D850F5, 0x3F9B762C, 0x3B5A6B9B,
758 0x0315D626, 0x07D4CB91, 0x0A97ED48, 0x0E56F0FF,
759 0x1011A0FA, 0x14D0BD4D, 0x19939B94, 0x1D528623,
760
761 0xF12F560E, 0xF5EE4BB9, 0xF8AD6D60, 0xFC6C70D7,
762 0xE22B20D2, 0xE6EA3D65, 0xEBA91BBC, 0xEF68060B,
763 0xD727BBB6, 0xD3E6A601, 0xDEA580D8, 0xDA649D6F,
764 0xC423CD6A, 0xC0E2D0DD, 0xCDA1F604, 0xC960EBB3,
765
766 0xBD3E8D7E, 0xB9FF90C9, 0xB4BCB610, 0xB07DABA7,
767 0xAE3AFBA2, 0xAAFBE615, 0xA7B8C0CC, 0xA379DD7B,
768 0x9B3660C6, 0x9FF77D71, 0x92B45BA8, 0x9675461F,
769 0x8832161A, 0x8CF30BAD, 0x81B02D74, 0x857130C3,
770
771 0x5D8A9099, 0x594B8D2E, 0x5408ABF7, 0x50C9B640,
772 0x4E8EE645, 0x4A4FFBF2, 0x470CDD2B, 0x43CDC09C,
773 0x7B827D21, 0x7F436096, 0x7200464F, 0x76C15BF8,
774 0x68860BFD, 0x6C47164A, 0x61043093, 0x65C52D24,
775
776 0x119B4BE9, 0x155A565E, 0x18197087, 0x1CD86D30,
777 0x029F3D35, 0x065E2082, 0x0B1D065B, 0x0FDC1BEC,
778 0x3793A651, 0x3352BBE6, 0x3E119D3F, 0x3AD08088,
779 0x2497D08D, 0x2056CD3A, 0x2D15EBE3, 0x29D4F654,
780
781 0xC5A92679, 0xC1683BCE, 0xCC2B1D17, 0xC8EA00A0,
782 0xD6AD50A5, 0xD26C4D12, 0xDF2F6BCB, 0xDBEE767C,
783 0xE3A1CBC1, 0xE760D676, 0xEA23F0AF, 0xEEE2ED18,
784 0xF0A5BD1D, 0xF464A0AA, 0xF9278673, 0xFDE69BC4,
785
786 0x89B8FD09, 0x8D79E0BE, 0x803AC667, 0x84FBDBD0,
787 0x9ABC8BD5, 0x9E7D9662, 0x933EB0BB, 0x97FFAD0C,
788 0xAFB010B1, 0xAB710D06, 0xA6322BDF, 0xA2F33668,
789 0xBCB4666D, 0xB8757BDA, 0xB5365D03, 0xB1F740B4,
790 };
791
792 crc = 0xffffffff;
793
794 p = head;
795 while(p < tail){
796 crc = (crc << 8) ^ table[ ((crc >> 24) ^ p[0]) & 0xff ];
797 p += 1;
798 }
799
800 return crc;
801 }
802