|
MythTV
0.26-pre
|
00001 /* 00002 * Copyright (C) David C.J. Matthews 2005, 2006 00003 * Derived from libdsmcc by Richard Palmer 00004 */ 00005 //#include <stdio.h> 00006 #include <stdlib.h> 00007 #include <string.h> 00008 00009 #include "dsmccbiop.h" 00010 #include "dsmccreceiver.h" 00011 #include "dsmcccache.h" 00012 #include "dsmccobjcarousel.h" 00013 #include "dsmcc.h" 00014 00015 #include "mythlogging.h" 00016 00017 BiopNameComp::~BiopNameComp() 00018 { 00019 if (m_id) 00020 free(m_id); 00021 if (m_kind) 00022 free(m_kind); 00023 } 00024 00025 int BiopNameComp::Process(const unsigned char *data) 00026 { 00027 int off = 0; 00028 00029 m_id_len = data[off++]; 00030 m_id = (char*) malloc(m_id_len); 00031 memcpy(m_id, data + off, m_id_len); 00032 00033 off += m_id_len; 00034 m_kind_len = data[off++]; 00035 m_kind = (char*) malloc(m_kind_len); 00036 memcpy(m_kind, data + off, m_kind_len); 00037 00038 off += m_kind_len; 00039 00040 return off; 00041 } 00042 00043 BiopName::BiopName() 00044 { 00045 m_comp_count = 0; 00046 m_comps = NULL; 00047 } 00048 00049 BiopName::~BiopName() 00050 { 00051 delete[] m_comps; 00052 } 00053 00054 int BiopName::Process(const unsigned char *data) 00055 { 00056 int off = 0; 00057 m_comp_count = data[0]; 00058 00059 if (m_comp_count != 1) 00060 LOG(VB_DSMCC, LOG_WARNING, "[biop] Expected one name"); 00061 00062 off++; 00063 m_comps = new BiopNameComp[m_comp_count]; 00064 00065 for (int i = 0; i < m_comp_count; i++) 00066 { 00067 int ret = m_comps[i].Process(data + off); 00068 if (ret <= 0) 00069 return ret; 00070 off += ret; 00071 } 00072 00073 return off; 00074 } 00075 00076 int BiopBinding::Process(const unsigned char *data) 00077 { 00078 int off = 0, ret; 00079 ret = m_name.Process(data); 00080 00081 if (ret > 0) 00082 off += ret; 00083 else 00084 return ret; // Error 00085 00086 m_binding_type = data[off++]; 00087 ret = m_ior.Process(data + off); 00088 00089 if (ret > 0) 00090 off += ret; 00091 else 00092 return ret; // Error 00093 00094 m_objinfo_len = (data[off] << 8) | data[off + 1]; 00095 off += 2; 00096 00097 if (m_objinfo_len > 0) 00098 { 00099 m_objinfo = (char*) malloc(m_objinfo_len); 00100 memcpy(m_objinfo, data + off, m_objinfo_len); 00101 } 00102 else 00103 m_objinfo = NULL; 00104 00105 off += m_objinfo_len; 00106 00107 return off; 00108 } 00109 00110 BiopBinding::~BiopBinding() 00111 { 00112 free(m_objinfo); 00113 } 00114 00115 bool BiopMessage::Process(DSMCCCacheModuleData *cachep, DSMCCCache *filecache, 00116 unsigned char *data, unsigned long *curp) 00117 { 00118 // Parse header 00119 if (! ProcessMsgHdr(data, curp)) 00120 { 00121 LOG(VB_DSMCC, LOG_ERR, 00122 "[biop] Invalid biop header, dropping rest of module"); 00123 00124 /* not valid, skip rest of data */ 00125 return false; 00126 } 00127 00128 // Handle each message type 00129 if (strcmp(m_objkind, "fil") == 0) 00130 { 00131 LOG(VB_DSMCC, LOG_DEBUG, "[biop] Processing file"); 00132 return ProcessFile(cachep, filecache, data, curp); 00133 } 00134 else if (strcmp(m_objkind, "dir") == 0) 00135 { 00136 LOG(VB_DSMCC, LOG_DEBUG, "[biop] Processing directory"); 00137 return ProcessDir(false, cachep, filecache, data, curp); 00138 } 00139 else if (strcmp(m_objkind, "srg") == 0) 00140 { 00141 LOG(VB_DSMCC, LOG_DEBUG, "[biop] Processing gateway"); 00142 return ProcessDir(true, cachep, filecache, data, curp); 00143 } 00144 else 00145 { 00146 /* Error */ 00147 LOG(VB_DSMCC, LOG_WARNING, QString("Unknown or unsupported format %1%2%3%4") 00148 .arg(m_objkind[0]).arg(m_objkind[1]) 00149 .arg(m_objkind[2]).arg(m_objkind[3])); 00150 return false; 00151 } 00152 } 00153 00154 BiopMessage::~BiopMessage() 00155 { 00156 free(m_objinfo); 00157 free(m_objkind); 00158 } 00159 00160 bool BiopMessage::ProcessMsgHdr(unsigned char *data, unsigned long *curp) 00161 { 00162 const unsigned char *buf = data + (*curp); 00163 int off = 0; 00164 00165 if (buf[off] !='B' || buf[off +1] !='I' || buf[off +2] !='O' || buf[off +3] !='P') 00166 { 00167 LOG(VB_DSMCC, LOG_WARNING, "BiopMessage - invalid header"); 00168 return false; 00169 } 00170 off += 4; 00171 00172 m_version_major = buf[off++]; 00173 m_version_minor = buf[off++]; 00174 if (m_version_major != 1 || m_version_minor != 0) 00175 { 00176 LOG(VB_DSMCC, LOG_WARNING, "BiopMessage invalid version"); 00177 return false; 00178 } 00179 00180 if (buf[off++] != 0) 00181 { 00182 LOG(VB_DSMCC, LOG_WARNING, "BiopMessage invalid byte order"); 00183 return false; 00184 } 00185 if (buf[off++] != 0) 00186 { 00187 LOG(VB_DSMCC, LOG_WARNING, "BiopMessage invalid message type"); 00188 return false; 00189 } 00190 00191 m_message_size = ((buf[off + 0] << 24) | (buf[off+1] << 16) | 00192 (buf[off + 2] << 8) | (buf[off + 3])); 00193 off += 4; 00194 00195 uint nObjLen = buf[off++]; 00196 m_objkey = DSMCCCacheKey((const char*)buf + off, nObjLen); 00197 off += nObjLen; 00198 00199 m_objkind_len = ((buf[off + 0] << 24) | (buf[off + 1] << 16) | 00200 (buf[off + 2] << 8) | (buf[off + 3])); 00201 off += 4; 00202 m_objkind = (char*) malloc(m_objkind_len); 00203 memcpy(m_objkind, buf + off, m_objkind_len); 00204 off += m_objkind_len; 00205 00206 m_objinfo_len = buf[off] << 8 | buf[off + 1]; 00207 off += 2; 00208 m_objinfo = (char*) malloc(m_objinfo_len); 00209 memcpy(m_objinfo, buf + off, m_objinfo_len); 00210 off += m_objinfo_len; 00211 00212 (*curp) += off; 00213 00214 return true; 00215 } 00216 00217 00226 bool BiopMessage::ProcessDir( 00227 bool isSrg, DSMCCCacheModuleData *cachep, DSMCCCache *filecache, 00228 unsigned char *data, unsigned long *curp) 00229 { 00230 int off = 0; 00231 const unsigned char * const buf = data + (*curp); 00232 00233 if (m_objinfo_len) 00234 LOG(VB_DSMCC, LOG_WARNING, "[biop] ProcessDir non-zero objectInfo_length"); 00235 00236 const unsigned serviceContextList_count = buf[off++]; 00237 if (serviceContextList_count) 00238 { 00239 // TODO Handle serviceContextList for service gateway 00240 LOG(VB_DSMCC, LOG_WARNING, QString("[biop] ProcessDir serviceContextList count %1") 00241 .arg(serviceContextList_count)); 00242 return false; // Error 00243 } 00244 00245 unsigned long msgbody_len = ((buf[off + 0] << 24) | (buf[off + 1] << 16) | 00246 (buf[off + 2] << 8) | (buf[off + 3])); 00247 off += 4; 00248 int const start = off; 00249 00250 unsigned int bindings_count = buf[off] << 8 | buf[off + 1]; 00251 off += 2; 00252 00253 DSMCCCacheReference ref(cachep->CarouselId(), cachep->ModuleId(), 00254 cachep->StreamId(), m_objkey); 00255 DSMCCCacheDir *pDir = isSrg ? filecache->Srg(ref) : filecache->Directory(ref); 00256 00257 for (uint i = 0; i < bindings_count; i++) 00258 { 00259 BiopBinding binding; 00260 int ret = binding.Process(buf + off); 00261 if (ret > 0) 00262 off += ret; 00263 else 00264 return false; // Error 00265 00266 if (binding.m_name.m_comp_count != 1) 00267 LOG(VB_DSMCC, LOG_WARNING, "[biop] ProcessDir nameComponents != 1"); 00268 00269 if (binding.m_binding_type != 1 && binding.m_binding_type != 2) 00270 LOG(VB_DSMCC, LOG_WARNING, "[biop] ProcessDir invalid BindingType"); 00271 00272 // Process any taps in this binding. 00273 binding.m_ior.AddTap(filecache->m_Dsmcc); 00274 00275 if (pDir && binding.m_name.m_comp_count >= 1) 00276 { 00277 if (strcmp("fil", binding.m_name.m_comps[0].m_kind) == 0) 00278 filecache->AddFileInfo(pDir, &binding); 00279 else if (strcmp("dir", binding.m_name.m_comps[0].m_kind) == 0) 00280 filecache->AddDirInfo(pDir, &binding); 00281 else 00282 LOG(VB_DSMCC, LOG_WARNING, QString("[biop] ProcessDir unknown kind %1") 00283 .arg(binding.m_name.m_comps[0].m_kind)); 00284 } 00285 } 00286 00287 if ((unsigned)(off - start) != msgbody_len) 00288 LOG(VB_DSMCC, LOG_WARNING, "[biop] ProcessDir incorrect msgbody_len"); 00289 00290 (*curp) += off; 00291 00292 return true; 00293 } 00294 00295 bool BiopMessage::ProcessFile(DSMCCCacheModuleData *cachep, DSMCCCache *filecache, 00296 unsigned char *data, unsigned long *curp) 00297 { 00298 int off = 0; 00299 const unsigned char *buf = data + (*curp); 00300 unsigned long msgbody_len; 00301 unsigned long content_len; 00302 00303 if (m_objinfo_len != 8) 00304 LOG(VB_DSMCC, LOG_WARNING, QString("[biop] ProcessFile objectInfo_length = %1") 00305 .arg(m_objinfo_len)); 00306 00307 const unsigned serviceContextList_count = buf[off++]; 00308 if (serviceContextList_count) 00309 { 00310 LOG(VB_DSMCC, LOG_WARNING, 00311 QString("[biop] ProcessFile Unexpected serviceContextList_count %1") 00312 .arg(serviceContextList_count)); 00313 return false; // Error 00314 } 00315 00316 msgbody_len = ((buf[off ] << 24) | (buf[off + 1] << 16) | 00317 (buf[off + 2] << 8) | (buf[off + 3])); 00318 off += 4; 00319 content_len = ((buf[off ] << 24) | (buf[off + 1] << 16) | 00320 (buf[off + 2] << 8) | (buf[off + 3])); 00321 off += 4; 00322 if (content_len + 4 != msgbody_len) 00323 LOG(VB_DSMCC, LOG_WARNING, "[biop] ProcessFile incorrect msgbody_len"); 00324 00325 (*curp) += off; 00326 00327 DSMCCCacheReference ref(cachep->CarouselId(), cachep->ModuleId(), 00328 cachep->StreamId(), m_objkey); 00329 00330 QByteArray filedata = QByteArray((const char *)data+(*curp), content_len); 00331 filecache->CacheFileData(ref, filedata); 00332 00333 (*curp) += content_len; 00334 return true; 00335 } 00336 00337 void ModuleDescriptorData::Process(const unsigned char *data, int length) 00338 { 00339 while (length > 0) 00340 { 00341 unsigned char tag = *data++; 00342 unsigned char len = *data++; 00343 length -= 2; 00344 switch (tag) 00345 { 00346 case 0x01: // Type 00347 break; 00348 case 0x02: // Name 00349 break; 00350 case 0x03: // Info 00351 break; 00352 case 0x04: // Modlink 00353 break; 00354 case 0x05: // CRC 00355 break; 00356 case 0x06: // Location 00357 break; 00358 case 0x07: // DLtime 00359 break; 00360 case 0x08: // Grouplink 00361 break; 00362 case 0x09: // Compressed. 00363 // Skip the method. 00364 isCompressed = true; 00365 originalSize = ((data[1] << 24) | (data[2] << 16) | 00366 (data[3] << 8) | (data[4])); 00367 break; 00368 default: 00369 break; 00370 } 00371 length -= len; 00372 data += len; 00373 } 00374 } 00375 00376 int BiopModuleInfo::Process(const unsigned char *data) 00377 { 00378 int off, ret; 00379 mod_timeout = ((data[0] << 24) | (data[1] << 16) | 00380 (data[2] << 8) | (data[3])); 00381 block_timeout = ((data[4] << 24) | (data[5] << 16) | 00382 (data[6] << 8) | (data[7])); 00383 min_blocktime = ((data[8] << 24) | (data[9] << 16) | 00384 (data[10] << 8) | (data[11])); 00385 00386 taps_count = data[12]; 00387 off = 13; 00388 00389 LOG(VB_DSMCC, LOG_DEBUG, QString("[Biop] " 00390 "ModuleTimeout %1 BlockTimeout %2 MinBlockTime %3 Taps %4") 00391 .arg(mod_timeout).arg(block_timeout).arg(min_blocktime) 00392 .arg(taps_count)); 00393 00394 if (taps_count > 0) 00395 { 00396 /* only 1 allowed TODO - may not be first though ? */ 00397 ret = tap.Process(data + off); 00398 if (ret <= 0) 00399 return ret; 00400 off += ret; 00401 } 00402 00403 unsigned userinfo_len = data[off++]; 00404 00405 if (userinfo_len > 0) 00406 { 00407 descriptorData.Process(data + off, userinfo_len); 00408 off += userinfo_len; 00409 } 00410 return off; 00411 00412 } 00413 00414 int BiopTap::Process(const unsigned char *data) 00415 { 00416 int off=0; 00417 00418 id = (data[off] << 8) | data[off + 1]; // Ignored 00419 off += 2; 00420 use = (data[off] << 8) | data[off + 1]; 00421 off += 2; 00422 assoc_tag = (data[off] << 8) | data[off + 1]; 00423 off += 2; 00424 selector_len = data[off++]; 00425 selector_data = (char*) malloc(selector_len); 00426 memcpy(selector_data, data + off, selector_len); 00427 if (use == 0x0016) // BIOP_DELIVERY_PARA_USE 00428 { 00429 unsigned selector_type = (data[off] << 8) | data[off + 1]; 00430 if (selector_len >= 10 && selector_type == 0x0001) 00431 { 00432 off += 2; 00433 unsigned long transactionId = ((data[off] << 24) | (data[off + 1] << 16) | 00434 (data[off + 2] << 8) | (data[off + 3])); 00435 off += 4; 00436 unsigned long timeout = ((data[off] << 24) | (data[off + 1] << 16) | 00437 (data[off + 2] << 8) | (data[off + 3])); 00438 LOG(VB_DSMCC, LOG_DEBUG, QString("[biop] BIOP_DELIVERY_PARA_USE tag %1 id 0x%2 timeout %3uS") 00439 .arg(assoc_tag).arg(transactionId,0,16).arg(timeout)); 00440 off += 4; 00441 selector_len -= 10; 00442 } 00443 } 00444 00445 off += selector_len; 00446 return off; 00447 } 00448 00449 int BiopConnbinder::Process(const unsigned char *data) 00450 { 00451 int off = 0, ret; 00452 00453 component_tag = ((data[0] << 24) | (data[1] << 16) | 00454 (data[2] << 8) | (data[3])); 00455 if (0x49534F40 != component_tag) 00456 { 00457 LOG(VB_DSMCC, LOG_WARNING, "[biop] Invalid Connbinder tag"); 00458 return 0; 00459 } 00460 off += 4; 00461 component_data_len = data[off++]; 00462 taps_count = data[off++]; 00463 if (taps_count > 0) 00464 { 00465 /* UKProfile - only first tap read */ 00466 ret = tap.Process(data + off); 00467 #if 0 00468 LOG(VB_GENERAL, LOG_DEBUG, QString("Binder - assoc_tag %1") 00469 .arg(tap.assoc_tag)); 00470 #endif 00471 if (ret > 0) 00472 off += ret; 00473 /* else TODO error */ 00474 } 00475 00476 return off; 00477 } 00478 00479 int BiopObjLocation::Process(const unsigned char *data) 00480 { 00481 int off = 0; 00482 00483 component_tag = ((data[0] << 24) | (data[1] << 16) | 00484 (data[2] << 8) | (data[3])); 00485 if (0x49534F50 != component_tag) 00486 { 00487 LOG(VB_DSMCC, LOG_WARNING, "[biop] Invalid ObjectLocation tag"); 00488 return 0; 00489 } 00490 off += 4; 00491 00492 component_data_len = data[off++]; 00493 m_Reference.m_nCarouselId = 00494 ((data[off ] << 24) | (data[off + 1] << 16) | 00495 (data[off + 2] << 8) | (data[off + 3])); 00496 00497 off += 4; 00498 00499 m_Reference.m_nModuleId = (data[off] << 8) | data[off + 1]; 00500 off += 2; 00501 00502 version_major = data[off++]; 00503 version_minor = data[off++]; 00504 if (1 != version_major || 0 != version_minor) 00505 { 00506 LOG(VB_DSMCC, LOG_WARNING, "[biop] Invalid ObjectLocation version"); 00507 return 0; 00508 } 00509 00510 uint objKeyLen = data[off++]; /* <= 4 */ 00511 m_Reference.m_Key = DSMCCCacheKey((char*)data + off, objKeyLen); 00512 off += objKeyLen; 00513 return off; 00514 } 00515 00516 // A Lite profile body is used to refer to an object referenced through 00517 // a different PMT, We don't support that, at least at the moment. 00518 int ProfileBodyLite::Process(const unsigned char * /*data*/) 00519 { 00520 LOG(VB_DSMCC, LOG_WARNING, "Found LiteProfileBody - Not Implemented Yet"); 00521 return 0; 00522 } 00523 00524 int ProfileBodyFull::Process(const unsigned char *data) 00525 { 00526 int off = 0, ret; 00527 00528 data_len = ((data[off ] << 24) | (data[off + 1] << 16) | 00529 (data[off + 2] << 8) | (data[off + 3])); 00530 off += 4; 00531 00532 /* bit order */ 00533 if (data[off++] != 0) 00534 { 00535 LOG(VB_DSMCC, LOG_WARNING, "[biop] ProfileBody invalid byte order"); 00536 return 0; 00537 } 00538 00539 lite_components_count = data[off++]; 00540 if (lite_components_count < 2) 00541 { 00542 LOG(VB_DSMCC, LOG_WARNING, "[biop] ProfileBody invalid components_count"); 00543 return 0; 00544 } 00545 00546 ret = obj_loc.Process(data + off); 00547 if (ret <= 0) 00548 return ret; 00549 off += ret; 00550 00551 ret = dsm_conn.Process(data + off); 00552 if (ret <= 0) 00553 return ret; 00554 off += ret; 00555 00556 obj_loc.m_Reference.m_nStreamTag = dsm_conn.tap.assoc_tag; 00557 00558 /* UKProfile - ignore anything else */ 00559 00560 return off; 00561 } 00562 00563 int BiopIor::Process(const unsigned char *data) 00564 { 00565 int off = 0, ret; 00566 type_id_len = ((data[0] << 24) | (data[1] << 16) | 00567 (data[2] << 8) | (data[3])); 00568 type_id = (char*) malloc(type_id_len); 00569 off += 4; 00570 memcpy(type_id, data + off, type_id_len); 00571 off += type_id_len; 00572 00573 tagged_profiles_count = ((data[off ] << 24) | (data[off + 1] << 16) | 00574 (data[off + 2] << 8) | (data[off + 3])); 00575 if (tagged_profiles_count < 1) 00576 { 00577 LOG(VB_DSMCC, LOG_WARNING, "[biop] IOR missing taggedProfile"); 00578 return 0; 00579 } 00580 off += 4; 00581 00582 profile_id_tag = ((data[off ] << 24) | (data[off + 1] << 16) | 00583 (data[off + 2] << 8) | (data[off + 3])); 00584 off += 4; 00585 00586 if (profile_id_tag == 0x49534F06) // profile_id_tag == 0x49534F06 00587 { 00588 m_profile_body = new ProfileBodyFull; 00589 ret = m_profile_body->Process(data + off); 00590 if (ret <= 0) 00591 return ret; 00592 off += ret; 00593 } 00594 else if(profile_id_tag == 0x49534F05) // profile_id_tag == 0x49534F05 00595 { 00596 m_profile_body = new ProfileBodyLite; 00597 ret = m_profile_body->Process(data + off); 00598 if (ret <= 0) 00599 return ret; 00600 off += ret; 00601 } 00602 else 00603 { 00604 /* UKProfile - receiver may ignore other profiles */ 00605 LOG(VB_DSMCC, LOG_WARNING, QString("[biop] Unknown Ior profile 0x%1") 00606 .arg(profile_id_tag, 0, 16)); 00607 return 0; 00608 } 00609 00610 return off; 00611 } 00612 00613 // An IOR may refer to other streams. We may have to add taps for them. 00614 void BiopIor::AddTap(Dsmcc *pStatus) 00615 { 00616 DSMCCCacheReference *ref = m_profile_body->GetReference(); 00617 if (ref != NULL) 00618 pStatus->AddTap(ref->m_nStreamTag, ref->m_nCarouselId); 00619 } 00620 00621 BiopTap::~BiopTap() 00622 { 00623 free(selector_data); 00624 }
1.7.6.1