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
227void 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}
bool Process(DSMCCCacheModuleData *cachep, DSMCCCache *cache, unsigned char *data, unsigned long *curp)
Definition: dsmccbiop.cpp:110
DSMCCCacheModuleData contains information about a module and holds the blocks for a partly completed ...
unsigned char * AddModuleData(DsmccDb *ddb, const unsigned char *Data)
Add block to the module and create the module if it's now complete.
unsigned short ModuleId(void) const
unsigned char m_version
unsigned long CarouselId(void) const
unsigned long m_moduleSize
Total size.
bool m_completed
True if we have completed this module.
unsigned char Version(void) const
unsigned short m_moduleId
std::vector< QByteArray * > m_blocks
Block table. As blocks are received they are added to this table.
unsigned long m_receivedData
Size received so far.
unsigned long DataSize(void) const
Return the, possibly uncompressed, module size.
DSMCCCacheModuleData(DsmccDii *dii, DsmccModuleInfo *info, unsigned short streamTag)
ModuleDescriptorData m_descriptorData
unsigned long ModuleSize(void) const
unsigned short m_blockNumber
Definition: dsmccreceiver.h:63
unsigned int m_len
Definition: dsmccreceiver.h:64
unsigned short m_moduleId
Definition: dsmccreceiver.h:61
unsigned char m_moduleVersion
Definition: dsmccreceiver.h:62
unsigned short m_numberModules
Definition: dsmccreceiver.h:22
unsigned short m_blockSize
Definition: dsmccreceiver.h:20
DsmccModuleInfo * m_modules
Definition: dsmccreceiver.h:24
unsigned long m_downloadId
Definition: dsmccreceiver.h:19
unsigned short m_moduleId
Definition: dsmccbiop.h:230
Definition: dsmcc.h:78
ObjCarousel * AddTap(unsigned short componentTag, unsigned carouselId)
Add a tap.
Definition: dsmcc.cpp:61
unsigned long m_originalSize
Definition: dsmccbiop.h:210
std::list< DSMCCCacheModuleData * > m_Cache
DSMCCCache m_fileCache
void AddModuleData(DsmccDb *ddb, const unsigned char *data)
We have received a block for a module.
void AddModuleInfo(DsmccDii *dii, Dsmcc *status, unsigned short streamTag)
unsigned long m_id
unsigned int uint
Definition: freesurround.h:24
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
dictionary info
Definition: azlyrics.py:7