00001
00002
00003
00004
00005 #include <stdint.h>
00006
00007 #include "mythlogging.h"
00008
00009 #include "dsmccreceiver.h"
00010 #include "dsmccbiop.h"
00011 #include "dsmcccache.h"
00012 #include "dsmcc.h"
00013
00014 #define DSMCC_SYNC_BYTE 0x47
00015 #define DSMCC_TRANSPORT_ERROR 0x80
00016 #define DSMCC_START_INDICATOR 0x40
00017
00018 #define DSMCC_MESSAGE_DSI 0x1006
00019 #define DSMCC_MESSAGE_DII 0x1002
00020 #define DSMCC_MESSAGE_DDB 0x1003
00021
00022 #define DSMCC_SECTION_INDICATION 0x3B
00023 #define DSMCC_SECTION_DATA 0x3C
00024 #define DSMCC_SECTION_DESCR 0x3D
00025
00026 #define DSMCC_SECTION_OFFSET 0
00027 #define DSMCC_MSGHDR_OFFSET 8
00028 #define DSMCC_DATAHDR_OFFSET 8
00029 #define DSMCC_DSI_OFFSET 20
00030 #define DSMCC_DII_OFFSET 20
00031 #define DSMCC_DDB_OFFSET 20
00032 #define DSMCC_BIOP_OFFSET 24
00033
00034 static uint32_t crc32(const unsigned char *data, int len);
00035
00036 Dsmcc::Dsmcc()
00037 {
00038 m_startTag = 0;
00039 }
00040
00041 Dsmcc::~Dsmcc()
00042 {
00043 Reset();
00044 }
00045
00049 ObjCarousel *Dsmcc::GetCarouselById(unsigned int carouselId)
00050 {
00051 QLinkedList<ObjCarousel*>::iterator it = carousels.begin();
00052
00053 for (; it != carousels.end(); ++it)
00054 {
00055 ObjCarousel *car = *it;
00056 if (car && car->m_id == carouselId)
00057 return car;
00058 }
00059 return NULL;
00060 }
00061
00070 ObjCarousel *Dsmcc::AddTap(unsigned short componentTag, unsigned carouselId)
00071 {
00072 ObjCarousel *car = GetCarouselById(carouselId);
00073
00074
00075
00076 if (car == NULL)
00077 {
00078 car = new ObjCarousel(this);
00079 carousels.append(car);
00080 car->m_id = carouselId;
00081 }
00082
00083
00084 vector<unsigned short>::iterator it;
00085 for (it = car->m_Tags.begin(); it != car->m_Tags.end(); ++it)
00086 {
00087 if (*it == componentTag)
00088 return car;
00089 }
00090
00091
00092 car->m_Tags.push_back(componentTag);
00093 LOG(VB_DSMCC, LOG_INFO, QString("[dsmcc] Adding tap for stream "
00094 "tag %1 with carousel %2")
00095 .arg(componentTag).arg(carouselId));
00096
00097 return car;
00098 }
00099
00100 bool Dsmcc::ProcessSectionHeader(DsmccSectionHeader *header,
00101 const unsigned char *data, int length)
00102 {
00103 int crc_offset = 0;
00104
00105 header->table_id = data[0];
00106 header->flags[0] = data[1];
00107 header->flags[1] = data[2];
00108
00109
00110
00111 if (((header->flags[0] & 0x80) == 0) || (header->flags[0] & 0x40) != 0)
00112 {
00113 LOG(VB_DSMCC, LOG_WARNING, "[dsmcc] Invalid section");
00114 return false;
00115 }
00116
00117
00118
00119 header->table_id_extension = (data[4] << 8) | data[5];
00120
00121 header->flags2 = data[6];
00122
00123 crc_offset = length - 4 - 1;
00124
00125
00126
00127 header->crc = ((data[crc_offset] << 24) | (data[crc_offset+1] << 16) |
00128 (data[crc_offset+2] << 8) | (data[crc_offset+3]));
00129
00130 return true;
00131 }
00132
00142 void Dsmcc::ProcessDownloadServerInitiate(const unsigned char *data,
00143 int length)
00144 {
00145
00146 int off;
00147 for (off = 0; off < 20; ++off)
00148 {
00149 if (data[off] != 0xff)
00150 {
00151 LOG(VB_DSMCC, LOG_WARNING, QString("[dsmcc] DSI invalid serverID"
00152 " index %1: 0x%2").arg(off).arg(data[off],0,16));
00153 return;
00154 }
00155 }
00156
00157
00158 if (data[off++] != 0 || data[off++] != 0)
00159 {
00160 LOG(VB_DSMCC, LOG_WARNING, "[dsmcc] DSI non zero compatibilityDescriptorLen");
00161 return;
00162 }
00163
00164
00165 int data_len = (data[off] << 8) | data[off+1];
00166 off += 2;
00167 if (data_len + off > length)
00168 {
00169 LOG(VB_DSMCC, LOG_WARNING, "[dsmcc] DSI ServiceGatewayInfo too big");
00170 return;
00171 }
00172
00173
00174 BiopIor gatewayProfile;
00175 int ret = gatewayProfile.Process(data+DSMCC_BIOP_OFFSET);
00176 if (ret <= 0)
00177 return;
00178
00179 if (strcmp(gatewayProfile.type_id, "srg"))
00180 {
00181 LOG(VB_DSMCC, LOG_WARNING, QString("[dsmcc] IOR unexpected type_id: '%1'")
00182 .arg(gatewayProfile.type_id));
00183 return;
00184 }
00185 if (ret + 4 > data_len)
00186 {
00187 LOG(VB_DSMCC, LOG_WARNING, "[dsmcc] DSI IOP:IOR too big");
00188 return;
00189 }
00190
00191 off += ret;
00192
00193
00194 gatewayProfile.AddTap(this);
00195
00196 DSMCCCacheReference *ref = gatewayProfile.m_profile_body->GetReference();
00197 unsigned carouselId = ref->m_nCarouselId;
00198 ObjCarousel *car = GetCarouselById(carouselId);
00199
00200
00201 ProfileBodyFull *full = dynamic_cast<ProfileBodyFull*>(gatewayProfile.m_profile_body);
00202 if (full)
00203 {
00204 LOG(VB_DSMCC, LOG_DEBUG, QString("[dsmcc] DSI ServiceGateway"
00205 " carousel %1 tag %2 module %3 key %4")
00206 .arg(carouselId).arg(full->dsm_conn.tap.assoc_tag)
00207 .arg(ref->m_nModuleId).arg(ref->m_Key.toString()));
00208
00209
00210 car = AddTap(full->dsm_conn.tap.assoc_tag, carouselId);
00211 }
00212 else
00213 {
00214 LOG(VB_DSMCC, LOG_INFO, QString("[dsmcc] DSI ServiceGateway"
00215 " carousel %1 module %2 key %3")
00216 .arg(carouselId).arg(ref->m_nModuleId)
00217 .arg(ref->m_Key.toString()));
00218 }
00219
00220
00221 if (car)
00222 car->filecache.SetGateway(*ref);
00223
00224
00225
00226
00227 unsigned short downloadTapsCount = data[off];
00228 off++;
00229 if (downloadTapsCount)
00230 {
00231 LOG(VB_DSMCC, LOG_WARNING, "[dsmcc] DSI unexpected downloadTap");
00232
00233 }
00234
00235 unsigned short serviceContextListCount = data[off];
00236 off++;
00237 if (serviceContextListCount)
00238 {
00239 LOG(VB_DSMCC, LOG_WARNING, "[dsmcc] DSI unexpected serviceContextList");
00240
00241 }
00242
00243 unsigned short userInfoLength = (data[off] << 8) | data[off+1];
00244 off += 2;
00245 if (userInfoLength)
00246 {
00247 LOG(VB_DSMCC, LOG_WARNING, "[dsmcc] DSI unexpected userInfo");
00248 off += userInfoLength;
00249 }
00250 }
00251
00252 void Dsmcc::ProcessDownloadInfoIndication(const unsigned char *data,
00253 unsigned short streamTag)
00254 {
00255 DsmccDii dii;
00256 int off = 0;
00257
00258 dii.download_id = ((data[0] << 24) | (data[1] << 16) |
00259 (data[2] << 8) | (data[3]));
00260
00261 ObjCarousel *car = GetCarouselById(dii.download_id);
00262
00263 if (car == NULL)
00264 {
00265 LOG(VB_DSMCC, LOG_ERR, QString("[dsmcc] Section Info for "
00266 "unknown carousel %1")
00267 .arg(dii.download_id));
00268
00269 return;
00270 }
00271
00272 off += 4;
00273 dii.block_size = data[off] << 8 | data[off+1];
00274 off += 2;
00275
00276 off += 6;
00277 dii.tc_download_scenario = ((data[off + 0] << 24) | (data[off + 1] << 16) |
00278 (data[off + 2] << 8) | (data[off + 3]));
00279 off += 4;
00280
00281
00282 off += 2;
00283 dii.number_modules = (data[off] << 8) | data[off + 1];
00284 off += 2;
00285 dii.modules = new DsmccModuleInfo[dii.number_modules];
00286
00287 for (uint i = 0; i < dii.number_modules; i++)
00288 {
00289 dii.modules[i].module_id = (data[off] << 8) | data[off + 1];
00290 off += 2;
00291 dii.modules[i].module_size =
00292 (data[off + 0] << 24) | (data[off + 1] << 16) |
00293 (data[off + 2] << 8) | (data[off + 3]);
00294 off += 4;
00295 dii.modules[i].module_version = data[off++];
00296 dii.modules[i].module_info_len = data[off++];
00297
00298 LOG(VB_DSMCC, LOG_DEBUG, QString("[dsmcc] Module %1 -> "
00299 "Size = %2 Version = %3")
00300 .arg(dii.modules[i].module_id)
00301 .arg(dii.modules[i].module_size)
00302 .arg(dii.modules[i].module_version));
00303
00304 int ret = dii.modules[i].modinfo.Process(data + off);
00305
00306 if (ret > 0)
00307 {
00308 off += ret;
00309 }
00310 else
00311 {
00312 return;
00313 }
00314 }
00315
00316 dii.private_data_len = (data[off] << 8) | data[off + 1];
00317
00318 car->AddModuleInfo(&dii, this, streamTag);
00319 return;
00320 }
00321
00322
00323 void Dsmcc::ProcessSectionIndication(const unsigned char *data,
00324 int length, unsigned short streamTag)
00325 {
00326 DsmccSectionHeader section;
00327 if (!ProcessSectionHeader(§ion, data + DSMCC_SECTION_OFFSET, length))
00328 return;
00329
00330 const unsigned char *hdrData = data + DSMCC_MSGHDR_OFFSET;
00331
00332 unsigned char protocol = hdrData[0];
00333 if (protocol != 0x11)
00334 {
00335 LOG(VB_DSMCC, LOG_WARNING, QString("[dsmcc] Server/Info invalid protocol %1")
00336 .arg(protocol));
00337 return;
00338 }
00339
00340 unsigned char header_type = hdrData[1];
00341 if (header_type != 0x03)
00342 {
00343 LOG(VB_DSMCC, LOG_WARNING, QString("[dsmcc] Server/Info invalid header type %1")
00344 .arg(header_type));
00345 return;
00346 }
00347
00348 unsigned message_id = (hdrData[2] << 8) | hdrData[3];
00349
00350
00351
00352
00353
00354
00355
00356 unsigned message_len = (hdrData[10] << 8) | hdrData[11];
00357 if (message_len > 4076)
00358 {
00359 LOG(VB_DSMCC, LOG_WARNING, QString("[dsmcc] Server/Info invalid length %1")
00360 .arg(message_len));
00361 return;
00362 }
00363
00364 if (message_id == DSMCC_MESSAGE_DSI)
00365 {
00366 LOG(VB_DSMCC, LOG_DEBUG, "[dsmcc] Server Gateway");
00367
00368
00369
00370 if (streamTag == m_startTag)
00371 {
00372 ProcessDownloadServerInitiate(data + DSMCC_DSI_OFFSET,
00373 length - DSMCC_DSI_OFFSET);
00374 }
00375 else
00376 {
00377 LOG(VB_DSMCC, LOG_WARNING,
00378 QString("[dsmcc] Discarding DSI from tag %1") .arg(streamTag));
00379 }
00380
00381 }
00382 else if (message_id == DSMCC_MESSAGE_DII)
00383 {
00384 LOG(VB_DSMCC, LOG_DEBUG, "[dsmcc] Module Info");
00385 ProcessDownloadInfoIndication(data + DSMCC_DII_OFFSET, streamTag);
00386 }
00387 else
00388 {
00389 LOG(VB_DSMCC, LOG_WARNING, "[dsmcc] Unknown section");
00390
00391 }
00392
00393 }
00394
00395
00396 void Dsmcc::ProcessSectionData(const unsigned char *data, int length)
00397 {
00398 DsmccSectionHeader section;
00399 if (!ProcessSectionHeader(§ion, data + DSMCC_SECTION_OFFSET, length))
00400 return;
00401
00402 const unsigned char *hdrData = data + DSMCC_DATAHDR_OFFSET;
00403
00404 unsigned char protocol = hdrData[0];
00405 if (protocol != 0x11)
00406 {
00407 LOG(VB_DSMCC, LOG_WARNING, QString("[dsmcc] Data invalid protocol %1")
00408 .arg(protocol));
00409 return;
00410 }
00411
00412 unsigned char header_type = hdrData[1];
00413 if (header_type != 0x03)
00414 {
00415 LOG(VB_DSMCC, LOG_WARNING, QString("[dsmcc] Data invalid header type %1")
00416 .arg(header_type));
00417 return;
00418 }
00419
00420 unsigned message_id = (hdrData[2] << 8) | hdrData[3];
00421 if (message_id != DSMCC_MESSAGE_DDB)
00422 {
00423 LOG(VB_DSMCC, LOG_WARNING, "[dsmcc] Data unknown section");
00424 return;
00425 }
00426
00427 unsigned long download_id = ((hdrData[4] << 24) | (hdrData[5] << 16) |
00428 (hdrData[6] << 8) | (hdrData[7]));
00429
00430
00431 unsigned message_len = (hdrData[10] << 8) | hdrData[11];
00432
00433 const unsigned char *blockData = data + DSMCC_DDB_OFFSET;
00434 DsmccDb ddb;
00435
00436 ddb.module_id = (blockData[0] << 8) | blockData[1];
00437 ddb.module_version = blockData[2];
00438
00439 ddb.block_number = (blockData[4] << 8) | blockData[5];
00440 ddb.len = message_len - 6;
00441
00442 LOG(VB_DSMCC, LOG_DEBUG,
00443 QString("[dsmcc] Data Block ModID %1 Pos %2 Version %3")
00444 .arg(ddb.module_id).arg(ddb.block_number).arg(ddb.module_version));
00445
00446 ObjCarousel *car = GetCarouselById(download_id);
00447 if (car != NULL)
00448 car->AddModuleData(&ddb, blockData + 6);
00449 else
00450 LOG(VB_DSMCC, LOG_WARNING, QString("[dsmcc] Data Block ModID %1 Pos %2"
00451 " unknown carousel %3")
00452 .arg(ddb.module_id).arg(ddb.block_number).arg(download_id));
00453
00454 return;
00455 }
00456
00457 void Dsmcc::ProcessSectionDesc(const unsigned char *data, int length)
00458 {
00459 DsmccSectionHeader section;
00460 ProcessSectionHeader(§ion, data + DSMCC_SECTION_OFFSET, length);
00461
00462
00463 }
00464
00465
00466 void Dsmcc::ProcessSection(const unsigned char *data, int length,
00467 int componentTag, unsigned carouselId,
00468 int dataBroadcastId)
00469 {
00470
00471 QLinkedList<ObjCarousel*>::iterator it = carousels.begin();
00472
00473 LOG(VB_DSMCC, LOG_DEBUG, QString("[dsmcc] Read block size %1 from tag %2 "
00474 "carousel id %3 data broadcast Id %4")
00475 .arg(length).arg(componentTag)
00476 .arg(carouselId).arg(dataBroadcastId,0,16));
00477
00478 bool found = false;
00479 for (; it != carousels.end(); ++it)
00480 {
00481 ObjCarousel *car = *it;
00482
00483 vector<unsigned short>::iterator it2;
00484 for (it2 = car->m_Tags.begin(); it2 != car->m_Tags.end(); ++it2)
00485 {
00486 if (*it2 == componentTag)
00487 {
00488 found = true;
00489 break;
00490 }
00491 }
00492 if (found)
00493 break;
00494 }
00495 if (!found && dataBroadcastId == 0x0106)
00496 {
00497
00498
00499
00500 if (AddTap(componentTag, carouselId))
00501 {
00502 m_startTag = componentTag;
00503 found = true;
00504 }
00505 }
00506
00507 if (!found)
00508 {
00509 LOG(VB_DSMCC, LOG_INFO, QString("[dsmcc] Dropping block size %1 with tag %2"
00510 ", carouselID %3, dataBroadcastID 0x%4")
00511 .arg(length).arg(componentTag).arg(carouselId)
00512 .arg(dataBroadcastId,0,16));
00513
00514 return;
00515 }
00516
00517 unsigned short section_len = ((data[1] & 0xF) << 8) | (data[2]);
00518 section_len += 3;
00519
00520 unsigned long crc32_decode = crc32(data, section_len);
00521
00522 if (crc32_decode != 0)
00523 {
00524 LOG(VB_DSMCC, LOG_WARNING,
00525 QString("[dsmcc] Dropping corrupt section (Got %1)")
00526 .arg(crc32_decode));
00527 return;
00528 }
00529
00530 switch (data[0])
00531 {
00532 case DSMCC_SECTION_INDICATION:
00533 LOG(VB_DSMCC, LOG_DEBUG, "[dsmcc] Server/Info Section");
00534 ProcessSectionIndication(data, length, componentTag);
00535 break;
00536 case DSMCC_SECTION_DATA:
00537 LOG(VB_DSMCC, LOG_DEBUG, "[dsmcc] Data Section");
00538 ProcessSectionData(data, length);
00539 break;
00540 case DSMCC_SECTION_DESCR:
00541 LOG(VB_DSMCC, LOG_DEBUG, "[dsmcc] Descriptor Section");
00542 ProcessSectionDesc(data, length);
00543 break;
00544 default:
00545 LOG(VB_DSMCC, LOG_WARNING, QString("[dsmcc] Unknown Section %1")
00546 .arg(data[0]));
00547 break;
00548 }
00549 }
00550
00551
00552 void Dsmcc::Reset()
00553 {
00554 LOG(VB_DSMCC, LOG_INFO, "Resetting carousel");
00555 QLinkedList<ObjCarousel*>::iterator it = carousels.begin();
00556 for (; it != carousels.end(); ++it)
00557 delete *it;
00558 carousels.clear();
00559 }
00560
00561 int Dsmcc::GetDSMCCObject(QStringList &objectPath, QByteArray &result)
00562 {
00563 QLinkedList<ObjCarousel*>::iterator it = carousels.begin();
00564
00565 if (it == carousels.end())
00566 return 1;
00567
00568
00569 for (; it != carousels.end(); ++it)
00570 {
00571 int res = (*it)->filecache.GetDSMObject(objectPath, result);
00572 if (res != -1)
00573 return res;
00574 }
00575
00576 return -1;
00577 }
00578
00579
00580
00581
00582 static unsigned long crc_table[256] =
00583 {
00584 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
00585 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
00586 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
00587 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
00588 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
00589 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
00590 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
00591 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
00592 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
00593 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
00594 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
00595 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
00596 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
00597 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
00598 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
00599 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
00600 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
00601 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
00602 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
00603 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
00604 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
00605 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
00606 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
00607 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
00608 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
00609 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
00610 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
00611 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
00612 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
00613 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
00614 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
00615 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
00616 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
00617 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
00618 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
00619 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
00620 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
00621 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
00622 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
00623 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
00624 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
00625 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
00626 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
00627 };
00628
00629 static uint32_t crc32(const unsigned char *data, int len)
00630 {
00631 register int i;
00632 uint32_t crc = 0xffffffff;
00633
00634 for (i = 0; i < len; i++)
00635 crc = (crc << 8) ^ crc_table[((crc >> 24) ^ *data++) & 0xff];
00636
00637 return crc;
00638 }