libflute
Classes | Public Types | Public Member Functions | List of all members
LibFlute::FileDeliveryTable Class Reference

A class for parsing and creating FLUTE FDTs (File Delivery Tables). More...

#include <FileDeliveryTable.h>

Classes

struct  FileEntry
 An entry for a file in the FDT. More...
 

Public Types

enum  FdtNamespace { FDT_NS_NONE = 0 , FDT_NS_RFC3926 , FDT_NS_DRAFT_2005 , FDT_NS_3GPP_CONSOLIDATED_V2 }
 FDT namespace enumeration. More...
 

Public Member Functions

 FileDeliveryTable (uint32_t instance_id, FecOti fec_oti, FdtNamespace fdt_namespace=FDT_NS_NONE)
 Create an empty FDT. More...
 
 FileDeliveryTable (uint32_t instance_id, char *buffer, size_t len)
 Parse an XML string and create a FDT class from it. More...
 
virtual ~FileDeliveryTable ()
 Default destructor. More...
 
uint32_t instance_id ()
 Get the FDT instance ID. More...
 
void set_expires (uint64_t exp)
 Set the expiry value. More...
 
void add (const FileEntry &entry)
 Add a file entry. More...
 
void remove (uint32_t toi)
 Remove a file entry. More...
 
std::string to_string () const
 Serialize the FDT to an XML string. More...
 
const std::vector< FileEntry > & file_entries () const
 Get all current file entries. More...
 
void sent ()
 Mark instance sent. More...
 

Detailed Description

A class for parsing and creating FLUTE FDTs (File Delivery Tables).

Definition at line 29 of file FileDeliveryTable.h.

Member Enumeration Documentation

◆ FdtNamespace

FDT namespace enumeration.

Enumerator
FDT_NS_NONE 
FDT_NS_RFC3926 
FDT_NS_DRAFT_2005 
FDT_NS_3GPP_CONSOLIDATED_V2 

Definition at line 34 of file FileDeliveryTable.h.

34  {
35  FDT_NS_NONE = 0,
38 // FDT_NS_RFC6726, // FLUTE v2 - will need other things implementing to use this correctly
40  };

Constructor & Destructor Documentation

◆ FileDeliveryTable() [1/2]

LibFlute::FileDeliveryTable::FileDeliveryTable ( uint32_t  instance_id,
FecOti  fec_oti,
FdtNamespace  fdt_namespace = FDT_NS_NONE 
)

Create an empty FDT.

Parameters
instance_idFDT instance ID to set
fec_otiGlobal FEC OTI parameters
fdt_namespaceThe XML namespace to use for FDT

Definition at line 134 of file FileDeliveryTable.cpp.

135  : _instance_id( instance_id )
136  , _instance_id_sent( instance_id - 1 )
137  , _global_fec_oti( fec_oti )
138  , _fdt_namespace( fdt_namespace )
139 {
140 }
uint32_t instance_id()
Get the FDT instance ID.

◆ FileDeliveryTable() [2/2]

LibFlute::FileDeliveryTable::FileDeliveryTable ( uint32_t  instance_id,
char *  buffer,
size_t  len 
)

Parse an XML string and create a FDT class from it.

Parameters
instance_idFDT instance ID (from ALC headers)
bufferString containing the FDT XML
lenLength of the buffer

Definition at line 142 of file FileDeliveryTable.cpp.

143  : _instance_id( instance_id )
144  , _instance_id_sent( instance_id - 1 )
145  , _global_fec_oti()
146 {
147  static const std::string mbms2007_ns("urn:3GPP:metadata:2007:MBMS:FLUTE:FDT"); // 3GPP TS 26.346 Clause 7.2.10.2
148  static const std::string mbms2012_ns("urn:3GPP:metadata:2012:MBMS:FLUTE:FDT"); // 3GPP TS 26.346 Clause 7.2.10.2
149  tinyxml2::XMLDocument doc(true, tinyxml2::COLLAPSE_WHITESPACE);
150  doc.Parse(buffer, len);
151  auto fdt_instance = doc.RootElement();
152  XMLNamespaces root_ns(fdt_instance);
153  auto fdt_ns = root_ns.elementNamespace(fdt_instance);
154  if (!root_ns.matches(fdt_instance->Name(), "FDT-Instance", fdt_ns)) {
155  throw "Root element is not FDT-Instance";
156  }
157 
158  if (fdt_ns == "") {
159  _fdt_namespace = FDT_NS_NONE;
160  } else if (fdt_ns == "http://www.example.com/flute") { // RFC 3926 Section 3.4.2
161  _fdt_namespace = FDT_NS_RFC3926;
162  } else if (fdt_ns == "urn:IETF:metadata:2005:FLUTE:FDT") { // 3GPP TS 26.346 Clause 7.2.10.1
163  _fdt_namespace = FDT_NS_DRAFT_2005;
164 // } else if (fdt_ns == "urn:ietf:params:xml:ns:fdt") { // RFC 6726 - FLUTEv2 - needs more work
165 // _fdt_namespace = FDT_NS_RFC6726;
166  } else if (fdt_ns == "urn:3GPP:metadata:2022:FLUTE:FDT") { // 3GPP TS 26.346 Clause L.6.1
167  _fdt_namespace = FDT_NS_3GPP_CONSOLIDATED_V2;
168  } else {
169  throw "FDT namespace not recognised";
170  }
171 
172  _expires = std::stoull(root_ns.findAttribute(fdt_instance, "Expires", fdt_ns)->Value());
173 
174  spdlog::debug("Received new FDT with instance ID {}: {}", instance_id, buffer);
175 
176  auto val = root_ns.findAttribute(fdt_instance, "FEC-OTI-FEC-Encoding-ID", fdt_ns);
177  if (val != nullptr) {
178  _global_fec_oti.encoding_id = static_cast<FecScheme>(strtoul(val->Value(), nullptr, 0));
179  }
180 
181  val = root_ns.findAttribute(fdt_instance, "FEC-OTI-FEC-Instance-ID", fdt_ns);
182  if (val != nullptr) {
183  _global_fec_oti.instance_id = strtoul(val->Value(), nullptr, 0);
184  }
185 
186  val = root_ns.findAttribute(fdt_instance, "FEC-OTI-Maximum-Source-Block-Length", fdt_ns);
187  if (val != nullptr) {
188  _global_fec_oti.max_source_block_length = strtoul(val->Value(), nullptr, 0);
189  }
190 
191  val = root_ns.findAttribute(fdt_instance, "FEC-OTI-Encoding-Symbol-Length", fdt_ns);
192  if (val != nullptr) {
193  _global_fec_oti.encoding_symbol_length = strtoul(val->Value(), nullptr, 0);
194  }
195 
196  val = root_ns.findAttribute(fdt_instance, "FEC-OTI-Max-Number-of-Encoding-Symbols", fdt_ns);
197  if (val != nullptr) {
198  _global_fec_oti.max_number_of_encoding_symbols = strtoul(val->Value(), nullptr, 0);
199  }
200 
201  for (auto file = root_ns.findChildElement(fdt_instance, "File", fdt_ns);
202  file != nullptr; file = root_ns.findSiblingElement(file, "File", fdt_ns)) {
203 
204  XMLNamespaces file_ns(file, root_ns);
205 
206  // File required attributes
207  auto toi_str = file_ns.findAttribute(file, "TOI", fdt_ns);
208  if (toi_str == nullptr) {
209  throw "Missing TOI attribute on File element";
210  }
211  uint32_t toi = strtoull(toi_str->Value(), nullptr, 0);
212 
213  auto content_location = file_ns.findAttribute(file, "Content-Location", fdt_ns);
214  if (content_location == nullptr) {
215  throw "Missing Content-Location attribute on File element";
216  }
217 
218  // File optional attributes
219  uint32_t content_length = 0;
220  val = file_ns.findAttribute(file, "Content-Length", fdt_ns);
221  if (val != nullptr) {
222  content_length = strtoull(val->Value(), nullptr, 0);
223  }
224 
225  uint32_t transfer_length = 0;
226  val = file_ns.findAttribute(file, "Transfer-Length", fdt_ns);
227  if (val != nullptr) {
228  transfer_length = strtoull(val->Value(), nullptr, 0);
229  } else {
230  transfer_length = content_length;
231  }
232 
233  auto content_md5 = std::string();
234  val = file_ns.findAttribute(file, "Content-MD5", fdt_ns);
235  if (val != nullptr) {
236  content_md5 = val->Value();
237  }
238 
239  auto content_encoding = std::string();
240  val = file_ns.findAttribute(file, "Content-Encoding", fdt_ns);
241  if (val != nullptr) {
242  content_encoding = val->Value();
243  }
244 
245  auto content_type = std::string();
246  val = file_ns.findAttribute(file, "Content-Type", fdt_ns);
247  if (val != nullptr) {
248  content_type = val->Value();
249  }
250 
251  auto encoding_id = _global_fec_oti.encoding_id;
252  val = file_ns.findAttribute(file, "FEC-OTI-FEC-Encoding-ID", fdt_ns);
253  if (val != nullptr) {
254  encoding_id = static_cast<FecScheme>(strtoul(val->Value(), nullptr, 0));
255  }
256 
257  auto fec_instance_id = _global_fec_oti.instance_id;
258  val = file_ns.findAttribute(file, "FEC-OTI-FEC-Instance-ID", fdt_ns);
259  if (val != nullptr) {
260  fec_instance_id = strtoul(val->Value(), nullptr, 0);
261  }
262 
263  auto max_source_block_length = _global_fec_oti.max_source_block_length;
264  val = file_ns.findAttribute(file, "FEC-OTI-Maximum-Source-Block-Length", fdt_ns);
265  if (val != nullptr) {
266  max_source_block_length = strtoul(val->Value(), nullptr, 0);
267  }
268 
269  auto encoding_symbol_length = _global_fec_oti.encoding_symbol_length;
270  val = file_ns.findAttribute(file, "FEC-OTI-Encoding-Symbol-Length", fdt_ns);
271  if (val != nullptr) {
272  encoding_symbol_length = strtoul(val->Value(), nullptr, 0);
273  }
274 
275  auto max_number_of_encoding_symbols = _global_fec_oti.max_number_of_encoding_symbols;
276  val = file_ns.findAttribute(file, "FEC-OTI-Max-Number-of-Encoding-Symbols", fdt_ns);
277  if (val != nullptr) {
278  max_number_of_encoding_symbols = strtoul(val->Value(), nullptr, 0);
279  }
280 
281  auto mbms2012_file_etag = "";
282  val = file_ns.findAttribute(file, "File-ETag", mbms2012_ns);
283  if (val != nullptr) {
284  mbms2012_file_etag = val->Value();
285  }
286 
287  // File optional elements
288 
289  bool no_cache = false;
290  //bool max_stale = false;
291  std::optional<uint64_t> cache_expires = std::nullopt;
292  auto cc = file_ns.findChildElement(file, "Cache-Control", mbms2007_ns);
293  if (cc) {
294  XMLNamespaces cc_ns(cc, file_ns);
295 
296  // mbms2007:Cache-Control optional elements
297 
298  auto no_cache_elem = cc_ns.findChildElement(cc, "no-cache", mbms2007_ns);
299  if (no_cache_elem) {
300  no_cache = true;
301  }
302 
303  //auto max_stale_elem = cc_ns.findChildElement(cc, "max-stale", mbms2007_ns);
304  //if (max_stale_elem) {
305  // max_stale = true;
306  //}
307 
308  auto expires_elem = cc_ns.findChildElement(cc, "Expires", mbms2007_ns);
309  if (expires_elem) {
310  cache_expires = strtoul(expires_elem->GetText(), nullptr, 0);
311  }
312  }
313 
314  FecOti fec_oti{
315  .encoding_id = (FecScheme)encoding_id,
316  .instance_id = fec_instance_id,
317  .transfer_length = transfer_length,
318  .encoding_symbol_length = encoding_symbol_length,
319  .max_source_block_length = max_source_block_length,
320  .max_number_of_encoding_symbols = max_number_of_encoding_symbols
321  };
322 
323  FileEntry fe{
324  toi,
325  std::string(content_location->Value()),
326  content_length,
327  content_md5,
328  content_type,
329  (cache_expires)?(cache_expires.value()):0,
330  fec_oti,
331  {
332  no_cache,
333  cache_expires
334  },
335  content_encoding,
336  mbms2012_file_etag
337  };
338  _file_entries.push_back(fe);
339  }
340 }
static char doc[]
FecScheme
Error correction schemes.
Definition: flute_types.h:44
uint32_t instance_id
Definition: flute_types.h:53
FecScheme encoding_id
Definition: flute_types.h:52
uint32_t max_source_block_length
Definition: flute_types.h:56
uint32_t max_number_of_encoding_symbols
Definition: flute_types.h:57
uint32_t encoding_symbol_length
Definition: flute_types.h:55

◆ ~FileDeliveryTable()

virtual LibFlute::FileDeliveryTable::~FileDeliveryTable ( )
inlinevirtual

Default destructor.

Definition at line 63 of file FileDeliveryTable.h.

63 {};

Member Function Documentation

◆ add()

auto LibFlute::FileDeliveryTable::add ( const FileEntry entry)

Add a file entry.

Definition at line 342 of file FileDeliveryTable.cpp.

343 {
344  if (_instance_id == _instance_id_sent) _instance_id++;
345  _file_entries.push_back(fe);
346 }

◆ file_entries()

const std::vector<FileEntry>& LibFlute::FileDeliveryTable::file_entries ( ) const
inline

Get all current file entries.

Definition at line 115 of file FileDeliveryTable.h.

115  {
116  return _file_entries;
117  };

◆ instance_id()

uint32_t LibFlute::FileDeliveryTable::instance_id ( )
inline

Get the FDT instance ID.

Definition at line 68 of file FileDeliveryTable.h.

68 { return _instance_id; };

◆ remove()

auto LibFlute::FileDeliveryTable::remove ( uint32_t  toi)

Remove a file entry.

Definition at line 348 of file FileDeliveryTable.cpp.

349 {
350  for (auto it = _file_entries.cbegin(); it != _file_entries.cend();) {
351  if (it->toi == toi) {
352  it = _file_entries.erase(it);
353  } else {
354  ++it;
355  }
356  }
357  if (_instance_id == _instance_id_sent) _instance_id++;
358 }

◆ sent()

void LibFlute::FileDeliveryTable::sent ( )
inline

Mark instance sent.

Definition at line 122 of file FileDeliveryTable.h.

122 { _instance_id_sent = _instance_id; };

◆ set_expires()

void LibFlute::FileDeliveryTable::set_expires ( uint64_t  exp)
inline

Set the expiry value.

Definition at line 95 of file FileDeliveryTable.h.

95 { _expires = exp; };

◆ to_string()

auto LibFlute::FileDeliveryTable::to_string ( ) const

Serialize the FDT to an XML string.

Definition at line 360 of file FileDeliveryTable.cpp.

360  {
361  tinyxml2::XMLDocument doc;
362  doc.InsertFirstChild( doc.NewDeclaration() );
363  auto root = doc.NewElement("FDT-Instance");
364  switch (_fdt_namespace) {
365  case FDT_NS_RFC3926:
366  // RFC 3926 Section 3.4.2
367  root->SetAttribute("xmlns", "http://www.example.com/flute");
368  break;
369  case FDT_NS_DRAFT_2005:
370  // 3GPP TS 26.346 Clause 7.2.10.1
371  root->SetAttribute("xmlns", "urn:IETF:metadata:2005:FLUTE:FDT");
372  break;
373 // case FDT_NS_RFC6726: // FLUTE v2 - Will need other things implementing to use this
374 // // RFC 6726
375 // root->SetAttribute("xmlns", "urn:ietf:params:xml:ns:fdt");
376 // break;
378  // 3GPP TS 26.346 Clause L.6.1
379  root->SetAttribute("xmlns", "urn:3GPP:metadata:2022:FLUTE:FDT");
380  break;
381  default:
382  break;
383  }
384  root->SetAttribute("Expires", std::to_string(_expires).c_str());
385  root->SetAttribute("FEC-OTI-FEC-Encoding-ID", (unsigned)_global_fec_oti.encoding_id);
386  if (_global_fec_oti.instance_id) root->SetAttribute("FEC-OTI-FEC-Instance-ID", (unsigned)_global_fec_oti.instance_id);
387  root->SetAttribute("FEC-OTI-Maximum-Source-Block-Length", (unsigned)_global_fec_oti.max_source_block_length);
388  root->SetAttribute("FEC-OTI-Encoding-Symbol-Length", (unsigned)_global_fec_oti.encoding_symbol_length);
389  root->SetAttribute("xmlns:mbms2007", "urn:3GPP:metadata:2007:MBMS:FLUTE:FDT"); // 3GPP TS 26.346 Clause 7.2.10.2
390  root->SetAttribute("xmlns:mbms2012", "urn:3GPP:metadata:2012:MBMS:FLUTE:FDT"); // 3GPP TS 26.346 Clause 7.2.10.2
391  doc.InsertEndChild(root);
392 
393  for (const auto& file : _file_entries) {
394  auto f = doc.NewElement("File");
395  f->SetAttribute("TOI", file.toi);
396  f->SetAttribute("Content-Location", file.content_location.c_str());
397  f->SetAttribute("Content-Length", file.content_length);
398  if (file.fec_oti.transfer_length) f->SetAttribute("Transfer-Length", file.fec_oti.transfer_length);
399  if (!file.content_md5.empty()) f->SetAttribute("Content-MD5", file.content_md5.c_str());
400  if (!file.content_encoding.empty()) f->SetAttribute("Content-Encoding", file.content_encoding.c_str());
401  if (!file.content_type.empty()) f->SetAttribute("Content-Type", file.content_type.c_str());
402  if (file.fec_oti.encoding_id != _global_fec_oti.encoding_id)
403  f->SetAttribute("FEC-OTI-FEC-Encoding-ID", (unsigned)file.fec_oti.encoding_id);
404  if (file.fec_oti.instance_id != 0 && file.fec_oti.instance_id != _global_fec_oti.instance_id)
405  f->SetAttribute("FEC-OTI-FEC-Instance-ID", (unsigned)file.fec_oti.instance_id);
406  if (file.fec_oti.max_source_block_length != 0 &&
407  file.fec_oti.max_source_block_length != _global_fec_oti.max_source_block_length)
408  f->SetAttribute("FEC-OTI-Maximum-Source-Block-Length", (unsigned)file.fec_oti.max_source_block_length);
409  if (file.fec_oti.encoding_symbol_length != 0 &&
410  file.fec_oti.encoding_symbol_length != _global_fec_oti.encoding_symbol_length)
411  f->SetAttribute("FEC-OTI-Encoding-Symbol-Length", (unsigned)file.fec_oti.encoding_symbol_length);
412  if (!file.etag.empty()) f->SetAttribute("mbms2012:File-ETag", file.etag.c_str());
413  if (file.cache_control.no_cache || file.cache_control.cache_expires) {
414  auto cc = doc.NewElement("mbms2007:Cache-Control");
415  if (file.cache_control.no_cache) {
416  auto noc = doc.NewElement("mbms2007:no-cache");
417  noc->SetText("true");
418  cc->InsertEndChild(noc);
419  } else {
420  auto exp = doc.NewElement("mbms2007:Expires");
421  exp->SetText(std::to_string(file.expires).c_str());
422  cc->InsertEndChild(exp);
423  }
424  f->InsertEndChild(cc);
425  }
426  root->InsertEndChild(f);
427  }
428 
429 
430  tinyxml2::XMLPrinter printer;
431  doc.Print(&printer);
432  return std::string(printer.CStr());
433 }

The documentation for this class was generated from the following files: