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