MythTV  master
dsmccobjcarousel.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) David C.J. Matthews 2005, 2006
3  * Derived from dsmcc by Richard Palmer
4  */
5 #include <cstdio>
6 #include <cstdlib>
7 #include <zlib.h>
8 #undef Z_NULL
9 #define Z_NULL nullptr
10 
11 #include "dsmccobjcarousel.h"
12 #include "dsmccreceiver.h"
13 #include "dsmcccache.h"
14 #include "dsmcc.h"
15 
16 #include "mythlogging.h"
17 
18 // Construct the data for a new module from a DII message.
20  DsmccModuleInfo *info,
21  unsigned short streamTag)
22  : m_carouselId(dii->m_downloadId), m_moduleId(info->m_moduleId),
23  m_streamId(streamTag), m_version(info->m_moduleVersion),
24  m_moduleSize(info->m_moduleSize)
25 {
26  // The number of blocks needed to hold this module.
27  int num_blocks = (m_moduleSize + dii->m_blockSize - 1) / dii->m_blockSize;
28  m_blocks.resize(num_blocks, nullptr); // Set it to all zeros
29 
30  // Copy the descriptor information.
32 }
33 
35 {
36  for (auto & block : m_blocks)
37  delete block;
38  m_blocks.clear();
39 }
40 
46  const unsigned char *data)
47 {
48  if (m_version != ddb->m_moduleVersion)
49  {
50  LOG(VB_DSMCC, LOG_WARNING, QString("[dsmcc] Module %1 my version %2 != %3")
51  .arg(ddb->m_moduleId).arg(m_version).arg(ddb->m_moduleVersion));
52  return nullptr; // Wrong version
53  }
54 
55  if (m_completed)
56  return nullptr; // Already got it.
57 
58  if (ddb->m_blockNumber >= m_blocks.size())
59  {
60  LOG(VB_DSMCC, LOG_WARNING, QString("[dsmcc] Module %1 block number %2 "
61  "is larger than %3")
62  .arg(ddb->m_moduleId).arg(ddb->m_blockNumber)
63  .arg(m_blocks.size()));
64  return nullptr;
65  }
66 
67  // Check if we have this block already or not. If not append to list
68  if (m_blocks[ddb->m_blockNumber])
69  {
70  QString s;
71  for (auto & block : m_blocks)
72  s += block ? '+' : 'X';
73 
74  LOG(VB_DSMCC, LOG_INFO, QString("[dsmcc] Module %1 block %2 dup: %3")
75  .arg(ddb->m_moduleId).arg(ddb->m_blockNumber +1).arg(s));
76 
77  return nullptr; // We have seen this block before.
78  }
79 
80  // Add this to our set of blocks.
81  m_blocks[ddb->m_blockNumber] = new QByteArray((char*) data, ddb->m_len);
82  if (m_blocks[ddb->m_blockNumber])
83  m_receivedData += ddb->m_len;
84 
85  LOG(VB_DSMCC, LOG_INFO, QString("[dsmcc] Module %1 block %2/%3 bytes %4/%5")
86  .arg(ddb->m_moduleId)
87  .arg(ddb->m_blockNumber +1).arg(m_blocks.size())
88  .arg(m_receivedData).arg(m_moduleSize));
89 
91  return nullptr; // Not yet complete
92 
93  LOG(VB_DSMCC, LOG_INFO,
94  QString("[dsmcc] Reconstructing module %1 from blocks")
95  .arg(m_moduleId));
96 
97  // Re-assemble the blocks into the complete module.
98  auto *tmp_data = (unsigned char*) malloc(m_receivedData);
99  if (tmp_data == nullptr)
100  return nullptr;
101 
102  uint curp = 0;
103  for (auto & block : m_blocks)
104  {
105  if (block == nullptr)
106  {
107  LOG(VB_DSMCC, LOG_INFO,
108  QString("[dsmcc] Null data found, aborting reconstruction"));
109  free(tmp_data);
110  return nullptr;
111  }
112  uint size = block->size();
113  memcpy(tmp_data + curp, block->data(), size);
114  curp += size;
115  delete block;
116  block = nullptr;
117  }
118 
119  /* Uncompress.... */
121  {
122  unsigned long dataLen = m_descriptorData.m_originalSize;
123  LOG(VB_DSMCC, LOG_INFO, QString("[dsmcc] uncompressing: "
124  "compressed size %1, final size %2")
125  .arg(m_moduleSize).arg(dataLen));
126 
127  auto *uncompressed = (unsigned char*) malloc(dataLen);
128  int ret = uncompress(uncompressed, &dataLen, tmp_data, m_moduleSize);
129  if (ret != Z_OK)
130  {
131  LOG(VB_DSMCC, LOG_ERR, "[dsmcc] compression error, skipping");
132  free(tmp_data);
133  free(uncompressed);
134  return nullptr;
135  }
136 
137  free(tmp_data);
138  tmp_data = uncompressed;
139  }
140 
141  m_completed = true;
142  m_blocks.clear(); // No longer required: free the space.
143  return tmp_data;
144 }
145 
146 
148 {
149  for (const auto & cache : m_Cache)
150  delete cache;
151  m_Cache.clear();
152 }
153 
155  unsigned short streamTag)
156 {
157  for (int i = 0; i < dii->m_numberModules; i++)
158  {
159  DsmccModuleInfo *info = &(dii->m_modules[i]);
160  bool bFound = false;
161  // Do we already know this module?
162  // If so and it is the same version we don't need to do anything.
163  // If the version has changed we have to replace it.
164  for (auto it = m_Cache.begin(); it != m_Cache.end(); ++it)
165  {
166  DSMCCCacheModuleData *cachep = *it;
167  if (cachep->CarouselId() == dii->m_downloadId &&
168  cachep->ModuleId() == info->m_moduleId)
169  {
170  /* already known */
171  if (cachep->Version() == info->m_moduleVersion)
172  {
173  LOG(VB_DSMCC, LOG_DEBUG, QString("[dsmcc] Already Know Module %1")
174  .arg(info->m_moduleId));
175 
176  if (cachep->ModuleSize() == info->m_moduleSize)
177  {
178  bFound = true;
179  break;
180  }
181  // It seems that when ITV4 starts broadcasting it
182  // updates the contents of a file but doesn't
183  // update the version. This is a work-around.
184  LOG(VB_DSMCC, LOG_ERR,
185  QString("[dsmcc] Module %1 size has changed (%2 to %3) "
186  "but version has not!!")
187  .arg(info->m_moduleId)
188  .arg(info->m_moduleSize)
189  .arg(cachep->DataSize()));
190  }
191  // Version has changed - Drop old data.
192  LOG(VB_DSMCC, LOG_INFO, QString("[dsmcc] Updated Module %1")
193  .arg(info->m_moduleId));
194 
195  // Remove and delete the cache object.
196  m_Cache.erase(it);
197  delete cachep;
198  break;
199  }
200  }
201 
202  if (bFound)
203  continue;
204 
205  LOG(VB_DSMCC, LOG_INFO, QString("[dsmcc] Saving info for module %1")
206  .arg(dii->m_modules[i].m_moduleId));
207 
208  // Create a new cache module data object.
209  auto *cachep = new DSMCCCacheModuleData(dii, info, streamTag);
210  int tag = info->m_modInfo.m_tap.m_assocTag;
211  LOG(VB_DSMCC, LOG_DEBUG, QString("[dsmcc] Module info tap identifies "
212  "tag %1 with carousel %2")
213  .arg(tag).arg(cachep->CarouselId()));
214 
215  // If a carousel with this id does not exist create it.
216  status->AddTap(tag, cachep->CarouselId());
217 
218  // Add this module to the cache.
219  m_Cache.push_back(cachep);
220  }
221 }
222 
228 void ObjCarousel::AddModuleData(DsmccDb *ddb, const unsigned char *data)
229 {
230  LOG(VB_DSMCC, LOG_DEBUG, QString("[dsmcc] Data block on carousel %1").arg(m_id));
231 
232  // Search the saved module info for this module
233  for (auto *cachep : m_Cache)
234  {
235  if (cachep->CarouselId() == m_id &&
236  (cachep->ModuleId() == ddb->m_moduleId))
237  {
238  // Add the block to the module
239  unsigned char *tmp_data = cachep->AddModuleData(ddb, data);
240  if (tmp_data)
241  {
242  // It is complete and we have the data
243  unsigned int len = cachep->DataSize();
244  unsigned long curp = 0;
245  LOG(VB_DSMCC, LOG_DEBUG, QString("[biop] Module size (uncompressed) = %1").arg(len));
246 
247  // Now process the BIOP tables in this module.
248  // Tables may be file contents or the descriptions of
249  // directories or service gateways (root directories).
250  while (curp < len)
251  {
252  BiopMessage bm;
253  if (!bm.Process(cachep, &m_fileCache, tmp_data, &curp))
254  break;
255  }
256  free(tmp_data);
257  }
258  return;
259  }
260  }
261  LOG(VB_DSMCC, LOG_INFO, QString("[dsmcc] Data block module %1 not on carousel %2")
262  .arg(ddb->m_moduleId).arg(m_id));
263 }
DSMCCCacheModuleData::m_completed
bool m_completed
True if we have completed this module.
Definition: dsmccobjcarousel.h:59
DSMCCCacheModuleData::CarouselId
unsigned long CarouselId(void) const
Definition: dsmccobjcarousel.h:33
DsmccModuleInfo::m_moduleVersion
unsigned char m_moduleVersion
Definition: dsmccbiop.h:232
BiopModuleInfo::m_tap
BiopTap m_tap
Definition: dsmccbiop.h:222
DsmccDb
Definition: dsmccreceiver.h:56
dsmcccache.h
DsmccDb::m_blockNumber
unsigned short m_blockNumber
Definition: dsmccreceiver.h:63
DSMCCCacheModuleData
DSMCCCacheModuleData contains information about a module and holds the blocks for a partly completed ...
Definition: dsmccobjcarousel.h:25
DsmccDii::m_downloadId
unsigned long m_downloadId
Definition: dsmccreceiver.h:19
DSMCCCacheModuleData::m_blocks
vector< QByteArray * > m_blocks
Block table. As blocks are received they are added to this table.
Definition: dsmccobjcarousel.h:57
DSMCCCacheModuleData::m_moduleSize
unsigned long m_moduleSize
Total size.
Definition: dsmccobjcarousel.h:53
dsmccobjcarousel.h
arg
arg(title).arg(filename).arg(doDelete))
DsmccModuleInfo::m_moduleId
unsigned short m_moduleId
Definition: dsmccbiop.h:230
DsmccDii::m_blockSize
unsigned short m_blockSize
Definition: dsmccreceiver.h:20
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
BiopTap::m_assocTag
unsigned short m_assocTag
Definition: dsmccbiop.h:56
ObjCarousel::AddModuleInfo
void AddModuleInfo(DsmccDii *dii, Dsmcc *status, unsigned short streamTag)
Definition: dsmccobjcarousel.cpp:154
DSMCCCacheModuleData::m_receivedData
unsigned long m_receivedData
Size received so far.
Definition: dsmccobjcarousel.h:54
mythlogging.h
DsmccDii
Definition: dsmccreceiver.h:11
DSMCCCacheModuleData::DataSize
unsigned long DataSize(void) const
Return the, possibly uncompressed, module size.
Definition: dsmccobjcarousel.h:40
BiopModuleInfo::m_descriptorData
ModuleDescriptorData m_descriptorData
Definition: dsmccbiop.h:224
ObjCarousel::AddModuleData
void AddModuleData(DsmccDb *ddb, const unsigned char *data)
We have received a block for a module.
Definition: dsmccobjcarousel.cpp:228
ObjCarousel::~ObjCarousel
~ObjCarousel()
Definition: dsmccobjcarousel.cpp:147
dsmccreceiver.h
DsmccDb::m_moduleVersion
unsigned char m_moduleVersion
Definition: dsmccreceiver.h:62
DsmccModuleInfo
Definition: dsmccbiop.h:228
ObjCarousel::m_id
unsigned long m_id
Definition: dsmccobjcarousel.h:75
DSMCCCacheModuleData::ModuleSize
unsigned long ModuleSize(void) const
Definition: dsmccobjcarousel.h:37
uint
unsigned int uint
Definition: compat.h:140
ModuleDescriptorData::m_isCompressed
bool m_isCompressed
Definition: dsmccbiop.h:209
Dsmcc::AddTap
ObjCarousel * AddTap(unsigned short componentTag, unsigned carouselId)
Add a tap.
Definition: dsmcc.cpp:57
DSMCCCacheModuleData::AddModuleData
unsigned char * AddModuleData(DsmccDb *ddb, const unsigned char *Data)
Add block to the module and create the module if it's now complete.
Definition: dsmccobjcarousel.cpp:45
ModuleDescriptorData::m_originalSize
unsigned long m_originalSize
Definition: dsmccbiop.h:210
DSMCCCacheModuleData::m_version
unsigned char m_version
Definition: dsmccobjcarousel.h:52
DsmccDb::m_len
unsigned int m_len
Definition: dsmccreceiver.h:64
Dsmcc
Definition: dsmcc.h:78
DsmccModuleInfo::m_modInfo
BiopModuleInfo m_modInfo
Definition: dsmccbiop.h:236
ObjCarousel::m_fileCache
DSMCCCache m_fileCache
Definition: dsmccobjcarousel.h:71
DsmccModuleInfo::m_moduleSize
unsigned long m_moduleSize
Definition: dsmccbiop.h:231
DsmccDii::m_numberModules
unsigned short m_numberModules
Definition: dsmccreceiver.h:22
ObjCarousel::m_Cache
std::list< DSMCCCacheModuleData * > m_Cache
Definition: dsmccobjcarousel.h:72
DSMCCCacheModuleData::Version
unsigned char Version(void) const
Definition: dsmccobjcarousel.h:36
BiopMessage
Definition: dsmccbiop.h:169
BiopMessage::Process
bool Process(DSMCCCacheModuleData *cachep, DSMCCCache *cache, unsigned char *data, unsigned long *curp)
Definition: dsmccbiop.cpp:108
DSMCCCacheModuleData::m_moduleId
unsigned short m_moduleId
Definition: dsmccobjcarousel.h:49
DSMCCCacheModuleData::ModuleId
unsigned short ModuleId(void) const
Definition: dsmccobjcarousel.h:34
DSMCCCacheModuleData::~DSMCCCacheModuleData
~DSMCCCacheModuleData()
Definition: dsmccobjcarousel.cpp:34
DSMCCCacheModuleData::DSMCCCacheModuleData
DSMCCCacheModuleData(DsmccDii *dii, DsmccModuleInfo *info, unsigned short streamTag)
Definition: dsmccobjcarousel.cpp:19
DsmccDii::m_modules
DsmccModuleInfo * m_modules
Definition: dsmccreceiver.h:24
dsmcc.h
DSMCCCacheModuleData::m_descriptorData
ModuleDescriptorData m_descriptorData
Definition: dsmccobjcarousel.h:60
DsmccDb::m_moduleId
unsigned short m_moduleId
Definition: dsmccreceiver.h:61