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