1 /* packet-scte35.c
2  * Routines for SCTE-35 dissection
3  * Author: Ben Stewart <bst[at]google.com>
4  * Copyright 2016 Google Inc.
5  *
6  * The SCTE-35 protocol is described by the Society of Cable Telecommunications
7  * Engineers at <https://www.scte.org/documents/pdf/Standards/Top%20Ten/ANSI_SCTE%2035%202013.pdf>.
8  *
9  * This module implements a dissector for the main table in a SCTE-35 message, a
10  * splice_info_section. This payload is carried in a MPEG Section Table with a
11  * table ID of 0xFC. PIDs carrying this sort of table are also noted in the PMT
12  * with a stream type of 0x86, and a registration descriptor with fourcc 'CUEI'.
13  *
14  * The various splice command types are implemented in separate modules, and are
15  * linked to this dissector through the field scte35.splice_command_type. All
16  * field names follow the conventions documented in the SCTE35 specification.
17  *
18  * This dissector does not support encrypted SCTE35 messages, other than
19  * indicating through the scte35.encrypted_packet flag.
20  *
21  *
22  * Wireshark - Network traffic analyzer
23  * By Gerald Combs <gerald@wireshark.org>
24  * Copyright 1998 Gerald Combs
25  *
26  * SPDX-License-Identifier: GPL-2.0-or-later
27  */
28 
29 #include "config.h"
30 
31 #include <epan/packet.h>
32 
33 #define SCTE35_CMD_SPLICE_NULL (0x00)
34 #define SCTE35_CMD_SPLICE_SCHEDULE (0x04)
35 #define SCTE35_CMD_SPLICE_INSERT (0x05)
36 #define SCTE35_CMD_TIME_SIGNAL (0x06)
37 #define SCTE35_CMD_BANDWIDTH_RESERVATION (0x07)
38 #define SCTE35_CMD_PRIVATE_COMMAND (0xff)
39 
40 #define SCTE35_AVAIL_DESCRIPTOR (0x00)
41 #define SCTE35_DTMF_DESCRIPTOR (0x01)
42 #define SCTE35_SEGMENTATION_DESCRIPTOR (0x02)
43 
44 void proto_register_scte35(void);
45 void proto_register_scte35_private_command(void);
46 void proto_register_scte35_splice_insert(void);
47 void proto_register_scte35_splice_schedule(void);
48 void proto_register_scte35_time_signal(void);
49 void proto_reg_handoff_scte35(void);
50 void proto_reg_handoff_scte35_private_command(void);
51 void proto_reg_handoff_scte35_splice_insert(void);
52 void proto_reg_handoff_scte35_splice_schedule(void);
53 void proto_reg_handoff_scte35_time_signal(void);
54 
55 /* MPEG Section Table ID for a SCTE35 splice_info_section. */
56 static const unsigned char SCTE35_TABLE_ID = 0xFCU;
57 
58 /* Minimum length for a splice_info_section, excluding any splice commands,
59  * splice descriptors, encrypted CRC or alignment stuffing.
60  */
61 static const int SCTE35_SI_MIN_LEN = 20;
62 
63 /* Protocol handle */
64 static int proto_scte35 = -1;
65 
66 /* Dissector table for scte35.splice_command_type */
67 static dissector_table_t scte35_cmd_dissector_table = NULL;
68 
69 
70 /* splice_info_section table */
71 static gint ett_scte35_splice_info_section = -1;
72 
73 /* splice_info_section fields */
74 static gint hf_table_id = -1;
75 static gint hf_section_syntax_indicator = -1;
76 static gint hf_private_indicator = -1;
77 static gint hf_reserved = -1;
78 static gint hf_section_length = -1;
79 static gint hf_protocol_version = -1;
80 static gint hf_encrypted_packet = -1;
81 static gint hf_encryption_algorithm = -1;
82 static gint hf_pts_adjustment = -1;
83 static gint hf_cw_index = -1;
84 static gint hf_tier = -1;
85 static gint hf_splice_command_length = -1;
86 static gint hf_splice_command_type = -1;
87 static gint hf_descriptor_loop_length = -1;
88 static gint hf_splice_descriptor_tag = -1;
89 static gint hf_splice_descriptor_length = -1;
90 static gint hf_splice_descriptor_identifier = -1;
91 static gint hf_descriptor_provider_avail_id = -1;
92 static gint hf_descriptor_preroll = -1;
93 static gint hf_descriptor_dtmf_count = -1;
94 static gint hf_descriptor_dtmf_reserved = -1;
95 static gint hf_descriptor_dtmf = -1;
96 static gint hf_descriptor_event_id = -1;
97 static gint hf_descriptor_cancel_indicator = -1;
98 static gint hf_descriptor_reserved0 = -1;
99 static gint hf_descriptor_psf = -1;
100 static gint hf_descriptor_segmentation_duration_flag = -1;
101 static gint hf_descriptor_delivery_not_restricted_flag = -1;
102 static gint hf_descriptor_web_delivery_allowed_flag = -1;
103 static gint hf_descriptor_no_regional_blackout_flag = -1;
104 static gint hf_descriptor_archive_allow_flag = -1;
105 static gint hf_descriptor_device_restrictions = -1;
106 static gint hf_descriptor_reserved1 = -1;
107 static gint hf_descriptor_component_count = -1;
108 static gint hf_descriptor_component_tag = -1;
109 static gint hf_descriptor_component_reserved = -1;
110 static gint hf_descriptor_component_pts_offset = -1;
111 static gint hf_descriptor_segmentation_duration = -1;
112 static gint hf_descriptor_segmentation_upid_type = -1;
113 static gint hf_descriptor_segmentation_upid_length = -1;
114 static gint hf_descriptor_segmentation_upid = -1;
115 static gint hf_descriptor_segmentation_type_id = -1;
116 static gint hf_descriptor_segment_num = -1;
117 static gint hf_descriptor_segments_expected = -1;
118 static gint hf_e_crc32 = -1;
119 static gint hf_crc32 = -1;
120 
121 /* time_signal protocol and fields */
122 static int proto_scte35_time = -1;
123 static gint ett_scte35_time_signal = -1;
124 static gint ett_scte35_time_signal_splice_time = -1;
125 static gint hf_time_specified = -1;
126 static gint hf_time_reserved = -1;
127 static gint hf_time_pts = -1;
128 
129 /* private_command protocol and fields */
130 static int proto_private_command = -1;
131 static gint ett_private_command = -1;
132 static gint hf_identifier = -1;
133 static gint hf_private_byte = -1;
134 
135 /* Dissector table for scte35_private_command.identifier */
136 static dissector_table_t private_identifier_table = NULL;
137 
138 static dissector_handle_t scte35_handle = NULL;
139 
140 /* splice_insert protocol and fields */
141 static int proto_scte35_si = -1;
142 static gint ett_scte35_splice_insert = -1;
143 static gint hf_splice_insert_event_id = -1;
144 static gint hf_splice_cancel_indicator = -1;
145 static gint hf_reserved0 = -1;
146 static gint hf_out_of_network_indicator = -1;
147 static gint hf_program_splice_flag = -1;
148 static gint hf_duration_flag = -1;
149 static gint hf_splice_immediate_flag = -1;
150 static gint hf_reserved1 = -1;
151 static gint hf_splice_time_specified_flag = -1;
152 static gint hf_splice_time_reserved = -1;
153 static gint hf_splice_time_pts_time = -1;
154 static gint hf_component_count = -1;
155 static gint hf_component_tag = -1;
156 static gint hf_component_splice_time_tsf = -1;
157 static gint hf_component_splice_time_reserved = -1;
158 static gint hf_component_splice_time_pts_time = -1;
159 static gint hf_break_duration_auto_return = -1;
160 static gint hf_break_duration_reserved = -1;
161 static gint hf_break_duration_duration = -1;
162 static gint hf_unique_program_id = -1;
163 static gint hf_avail_num = -1;
164 static gint hf_avails_expected = -1;
165 
166 /* splice_schedule protocol and fields */
167 static int proto_scte35_splice_schedule = -1;
168 static gint ett_scte35_splice_schedule = -1;
169 static gint hf_splice_count = -1;
170 static gint hf_splice_event_id = -1;
171 static gint hf_splice_event_cancel_indicator = -1;
172 static gint hf_splice_reserved0 = -1;
173 static gint hf_splice_out_of_network = -1;
174 static gint hf_splice_program_splice_flag = -1;
175 static gint hf_splice_duration_flag = -1;
176 static gint hf_splice_reserved1 = -1;
177 static gint hf_splice_utc_splice_time = -1;
178 static gint hf_splice_component_count = -1;
179 static gint hf_splice_component_tag = -1;
180 static gint hf_splice_component_utc_splice_time = -1;
181 static gint hf_splice_break_duration_auto_return = -1;
182 static gint hf_splice_break_duration_reserved = -1;
183 static gint hf_splice_break_duration_duration = -1;
184 static gint hf_splice_unique_program_id = -1;
185 static gint hf_splice_avail_num = -1;
186 static gint hf_splice_avails_expected = -1;
187 
188 static const true_false_string tfs_section_syntax_indicator = {
189     "Reserved", "MPEG short sections in use"};
190 
191 static const true_false_string tfs_private_indicator = {
192     "Reserved", "Mandatory value"};
193 
194 static const true_false_string tfs_encrypted_packet = {
195     "Encrypted data", "Cleartext"};
196 
197 static const true_false_string tfs_descriptor_cancel_indicator = {
198     "Cancel Request", "New or existing event"};
199 
200 static const true_false_string tfs_descriptor_psf = {
201     "All PIDs to be spliced", "Component Splice Mode"};
202 
203 static const true_false_string tfs_descriptor_sdf = {
204     "Segmentation duration present", "No duration present"};
205 
206 static const true_false_string tfs_descriptor_dnr = {
207     "No delivery restrictions", "Restricted delivery"};
208 
209 static const true_false_string tfs_descriptor_web = {
210     "Permitted", "Restricted"};
211 
212 static const true_false_string tfs_descriptor_blackout = {
213     "No regional blackouts", "Regional restrictions"};
214 
215 static const true_false_string tfs_descriptor_archive = {
216     "No recording restrictions", "Recording is restricted"};
217 
218 static const range_string rv_splice_command_type[] = {
219     { SCTE35_CMD_SPLICE_NULL, SCTE35_CMD_SPLICE_NULL, "splice_null" },
220     { 0x01, 0x03, "Reserved" },
221     { SCTE35_CMD_SPLICE_SCHEDULE, SCTE35_CMD_SPLICE_SCHEDULE, "splice_schedule" },
222     { SCTE35_CMD_SPLICE_INSERT, SCTE35_CMD_SPLICE_INSERT, "splice_insert" },
223     { SCTE35_CMD_TIME_SIGNAL, SCTE35_CMD_TIME_SIGNAL, "time_signal" },
224     { SCTE35_CMD_BANDWIDTH_RESERVATION, SCTE35_CMD_BANDWIDTH_RESERVATION, "bandwidth_reservation" },
225     { 0x08, 0xfe, "Reserved" },
226     { SCTE35_CMD_PRIVATE_COMMAND, SCTE35_CMD_PRIVATE_COMMAND, "private_command" },
227     {    0,    0, NULL }
228 };
229 
230 static const range_string rv_splice_descriptor_tag[] = {
231     { SCTE35_AVAIL_DESCRIPTOR,        SCTE35_AVAIL_DESCRIPTOR,        "avail_descriptor" },
232     { SCTE35_DTMF_DESCRIPTOR,         SCTE35_DTMF_DESCRIPTOR,         "DTMF_descriptor" },
233     { SCTE35_SEGMENTATION_DESCRIPTOR, SCTE35_SEGMENTATION_DESCRIPTOR, "segmentation_descriptor" },
234     { 0x03, 0xff, "Reserved" },
235     {    0,    0, NULL }
236 };
237 
238 static const range_string scte35_device_restrictions[] = {
239     { 0x00, 0x00, "Restrict Group 0" },
240     { 0x01, 0x01, "Restrict Group 1" },
241     { 0x02, 0x02, "Restrict Group 2" },
242     { 0x03, 0x03, "No Restrictions" },
243     {    0,    0, NULL }
244 };
245 
246 static const range_string scte35_segmentation_upid_type[] = {
247     { 0x00, 0x00, "Not Used" },
248     { 0x01, 0x01, "User Defined (deprecated)" },
249     { 0x02, 0x02, "ISCI" },
250     { 0x03, 0x03, "Ad-ID" },
251     { 0x04, 0x04, "UMID (SMPTE 330M)" },
252     { 0x05, 0x05, "ISAN" },
253     { 0x06, 0x06, "Versioned ISAN" },
254     { 0x07, 0x07, "Tribune TID" },
255     { 0x08, 0x08, "Turner Identifier" },
256     { 0x09, 0x09, "CableLabs ADI Identifier" },
257     { 0x0a, 0x0a, "EIDR" },
258     { 0x0b, 0x0b, "ATSC A57/B Content Identifier" },
259     { 0x0c, 0x0c, "Managed Private UPID" },
260     { 0x0d, 0x0d, "Multiple UPIDs" },
261     { 0x0e, 0xff, "Reserved" },
262     {    0,    0, NULL }
263 };
264 
265 static const range_string scte35_segmentation_type_id[] = {
266     { 0x00, 0x00, "Not Indicated" },
267     { 0x01, 0x01, "Content Identification" },
268     { 0x10, 0x10, "Program Start" },
269     { 0x11, 0x11, "Program End" },
270     { 0x12, 0x12, "Program Early Termination" },
271     { 0x13, 0x13, "Program Breakaway" },
272     { 0x14, 0x14, "Program Resumption" },
273     { 0x15, 0x15, "Program Runover Planned" },
274     { 0x16, 0x16, "Program Runover Unplanned" },
275     { 0x17, 0x17, "Program Overlap Start" },
276     { 0x20, 0x20, "Chapter Start" },
277     { 0x21, 0x21, "Chapter End" },
278     { 0x30, 0x30, "Provider Advertisement Start" },
279     { 0x31, 0x31, "Provider Advertisement End" },
280     { 0x32, 0x32, "Distributor Advertisement Start" },
281     { 0x33, 0x33, "Distributor Advertisement End" },
282     { 0x34, 0x34, "Placement Opportunity Start" },
283     { 0x35, 0x35, "Placement Opportunity End" },
284     { 0x40, 0x40, "Unscheduled Event Start" },
285     { 0x41, 0x41, "Unscheduled Event End" },
286     {    0,    0, NULL }
287 };
288 
289 static const range_string rv_encryption_algorithm[] = {
290     { 0x00, 0x00, "No encryption"},
291     { 0x01, 0x01, "DES - ECB mode"},
292     { 0x02, 0x02, "DES - CBC mode"},
293     { 0x03, 0x03, "Triple DES EDE3 - ECB mode"},
294     { 0x04, 0x1F, "Reserved"},
295     { 0x20, 0x3F, "User private"},
296     {    0,    0, NULL }
297 };
298 
299 
300 /* time_signal dissector */
301 static int
dissect_scte35_time_signal(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)302 dissect_scte35_time_signal(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
303     gint tvb_len, min_length = 1, offset = 0;
304     guint8 time_specified_flag;
305     proto_item *ti;
306     proto_tree *time_tree;
307 
308     /* Check packet length. */
309     tvb_len = (gint)tvb_reported_length(tvb);
310     if (tvb_len < min_length)
311         return 0;
312 
313     time_specified_flag = tvb_get_guint8(tvb, offset) & 0x80;
314     if (time_specified_flag)
315         min_length += 4;
316     if (tvb_len < min_length)
317         return 0;
318 
319     /* Set up headers in the packet list */
320     col_add_fstr(pinfo->cinfo, COL_INFO, "Time Signal (%s)",
321                  time_specified_flag ? "Future" : "Immediate");
322 
323     /* Create a subtee for the time_signal */
324     ti = proto_tree_add_item(tree, proto_scte35_time, tvb, 0, -1, ENC_NA);
325     time_tree = proto_item_add_subtree(ti, ett_scte35_time_signal);
326 
327     /* Parse out the fields. */
328     proto_tree_add_item(time_tree, hf_time_specified, tvb, offset, 1, ENC_BIG_ENDIAN);
329     proto_tree_add_item(time_tree, hf_time_reserved, tvb, offset, 1, ENC_BIG_ENDIAN);
330     if (time_specified_flag) {
331         proto_tree_add_item(time_tree, hf_time_pts, tvb, offset, 5, ENC_BIG_ENDIAN);
332         offset += 4;
333     }
334     offset += 1;
335 
336     return offset;
337 }
338 
339 void
proto_register_scte35_time_signal(void)340 proto_register_scte35_time_signal(void)
341 {
342     static gint *ett[] = {
343         &ett_scte35_time_signal,
344         &ett_scte35_time_signal_splice_time,
345     };
346 
347     static hf_register_info hf[] = {
348         {&hf_time_specified,
349          {"Time Specified", "scte35_time.splice.time_specified", FT_BOOLEAN, 8,
350              NULL, 0x80, NULL, HFILL}},
351         {&hf_time_reserved,
352          {"Reserved", "scte35_time.splice.reserved", FT_UINT8, BASE_HEX,
353              NULL, 0x7E, NULL, HFILL}},
354         {&hf_time_pts,
355          {"PTS Time", "scte35_time.splice.pts", FT_UINT64, BASE_DEC,
356              NULL, G_GUINT64_CONSTANT(0x1FFFFFFFF), NULL, HFILL}},
357     };
358 
359     proto_scte35_time = proto_register_protocol("SCTE-35 Time Signal", "SCTE35 TS", "scte35_time");
360     proto_register_subtree_array(ett, array_length(ett));
361     proto_register_field_array(proto_scte35_time, hf, array_length(hf));
362 }
363 
364 void
proto_reg_handoff_scte35_time_signal(void)365 proto_reg_handoff_scte35_time_signal(void)
366 {
367     dissector_handle_t scte35_time_handle;
368 
369     /* Create a dissector for time_signal packets. */
370     scte35_time_handle = create_dissector_handle(dissect_scte35_time_signal, proto_scte35_time);
371 
372     /* And hook it up to SCTE-35 messages. */
373     dissector_add_uint("scte35.splice_command_type", SCTE35_CMD_TIME_SIGNAL, scte35_time_handle);
374 }
375 
376 
377 /* scte35 private_command dissector */
378 static int
dissect_scte35_private_command(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)379 dissect_scte35_private_command(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
380 {
381     gint tvb_len;
382     guint32 identifier;
383     gint offset = 0;
384     proto_item *ti;
385     proto_tree *pc_tree;
386 
387     tvb_len = (gint)tvb_reported_length(tvb);
388     if (tvb_len < 4)
389         return 0;
390 
391     /* Display rudimentary header information. */
392     ti = proto_tree_add_item(tree, proto_private_command, tvb, 0, -1, ENC_NA);
393     pc_tree = proto_item_add_subtree(ti, ett_private_command);
394 
395     proto_tree_add_item_ret_uint(pc_tree, hf_identifier, tvb, offset, 4, ENC_BIG_ENDIAN, &identifier);
396     col_add_fstr(pinfo->cinfo, COL_INFO, "Private Command (0x%08x)", identifier);
397     offset += 4;
398     proto_tree_add_item(pc_tree, hf_private_byte, tvb, offset, -1, ENC_NA);
399 
400     /* Let another dissector try to decode this data. */
401     dissector_try_uint(private_identifier_table, identifier, tvb, pinfo, tree);
402 
403     return tvb_len;
404 }
405 
406 void
proto_register_scte35_private_command(void)407 proto_register_scte35_private_command(void)
408 {
409     static gint *ett[] = {
410         &ett_private_command,
411     };
412 
413     static hf_register_info hf[] = {
414         {&hf_identifier,
415          {"Identifier", "scte35_private_command.identifier", FT_UINT32,
416            BASE_HEX, NULL, 0, NULL, HFILL}},
417         {&hf_private_byte,
418           {"Private Bytes", "scte35_private_command.private_byte", FT_BYTES, 0,
419             NULL, 0, NULL, HFILL}},
420     };
421 
422     proto_private_command = proto_register_protocol("SCTE-35 Private Command", "SCTE35 PC", "scte35_private_command");
423 
424     proto_register_subtree_array(ett, array_length(ett));
425     proto_register_field_array(proto_private_command, hf, array_length(hf));
426 
427     /* Allow other modules to hook private commands and decode them. */
428     private_identifier_table = register_dissector_table(
429         "scte35_private_command.identifier", "SCTE-35 Private Command Identifier",
430         proto_private_command, FT_UINT32, BASE_HEX);
431 }
432 
433 void
proto_reg_handoff_scte35_private_command(void)434 proto_reg_handoff_scte35_private_command(void)
435 {
436     dissector_handle_t scte35_private_command_handle;
437 
438     /* Create a dissector for private commands. */
439     scte35_private_command_handle = create_dissector_handle(dissect_scte35_private_command, proto_private_command);
440 
441     /* Trigger our dissector on any private_command SCTE-35 messages. */
442     dissector_add_uint("scte35.splice_command_type", SCTE35_CMD_PRIVATE_COMMAND, scte35_private_command_handle);
443 }
444 
445 
446 /* scte35 splice_insert dissector */
447 static int
dissect_component(tvbuff_t * tvb,packet_info * pinfo _U_,proto_tree * tree,guint8 sif,int idx)448 dissect_component(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint8 sif, int idx)
449 {
450     gint offset = 0;
451     guint8 component_tag, tsf = 0;
452     proto_tree *component_tree;
453     gint tvb_len, min_length = sif ? 1 : 2;
454 
455     tvb_len = (gint)tvb_reported_length(tvb);
456     if (tvb_len < min_length)
457         return 0;
458 
459     if (!sif) {
460         /* Check whether time is present in the component. */
461         tsf = tvb_get_guint8(tvb, offset + 1) & 0x80;
462         if (tsf) {
463             min_length += 4;
464             if (tvb_len < min_length)
465                 return 0;
466         }
467     }
468 
469     /* Create a subtree for the component. */
470     component_tag = tvb_get_guint8(tvb, offset);
471     proto_tree_add_subtree_format(
472         tree, tvb, offset, min_length, idx, &component_tree,
473         "Component %d (0x%02x)", idx, component_tag);
474 
475     /* Parse out component flags. */
476     proto_tree_add_item(component_tree, hf_component_tag, tvb, offset, 1, ENC_BIG_ENDIAN);
477     offset++;
478 
479     /* For non-immediate splices.. */
480     if (!sif) {
481         proto_tree_add_item(component_tree, hf_component_splice_time_tsf, tvb,
482                             offset, 1, ENC_BIG_ENDIAN);
483         proto_tree_add_item(component_tree, hf_component_splice_time_reserved,
484                             tvb, offset, 1, ENC_BIG_ENDIAN);
485 
486         /* And the PTS if present. */
487         if (tsf) {
488             proto_tree_add_item(component_tree, hf_component_splice_time_pts_time,
489                 tvb, offset, 5, ENC_BIG_ENDIAN);
490             offset += 4;
491         }
492         offset++;
493     }
494 
495     return offset;
496 }
497 
498 static int
dissect_scte35_splice_insert(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)499 dissect_scte35_splice_insert(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
500 {
501     gint tvb_len, min_length = 5, dissected_length;
502     guint8 cancel_flag, psf, df, sif, tsf, component_count;
503     guint32 event_id;
504     gint component;
505     gint offset = 0;
506     proto_item *ti;
507     proto_tree *si_tree, *st_tree;
508 
509     static int * const new_event_fields[] = {
510         &hf_out_of_network_indicator,
511         &hf_program_splice_flag,
512         &hf_duration_flag,
513         &hf_splice_immediate_flag,
514         &hf_reserved1,
515         NULL
516     };
517 
518     /* Check with no optional subfields */
519     tvb_len = (gint)tvb_reported_length(tvb);
520     if (tvb_len < min_length)
521         return 0;
522 
523     cancel_flag = tvb_get_guint8(tvb, offset + 4) & 0x80;
524     event_id = tvb_get_ntohl(tvb, 0);
525 
526     if (!cancel_flag) {
527         min_length += 5;
528         if (tvb_len < min_length)
529             return 0;
530     }
531 
532     /* Set up headers in the packet list */
533     col_add_fstr(pinfo->cinfo, COL_INFO, "Splice %s Event 0x%08x",
534                  cancel_flag ? "Cancellation" : "Insertion", event_id);
535 
536     /* Create a root tree element for the splice_insert protocol. */
537     ti = proto_tree_add_item(tree, proto_scte35_si, tvb, 0, -1, ENC_NA);
538     si_tree = proto_item_add_subtree(ti, ett_scte35_splice_insert);
539 
540     /* Parse header fields */
541     proto_tree_add_item(si_tree, hf_splice_insert_event_id, tvb, offset, 4, ENC_BIG_ENDIAN);
542     offset += 4;
543 
544     proto_tree_add_item(si_tree, hf_splice_cancel_indicator, tvb, offset, 1, ENC_BIG_ENDIAN);
545     proto_tree_add_item(si_tree, hf_reserved0, tvb, offset, 1, ENC_BIG_ENDIAN);
546     offset++;
547 
548     /* Check for a new event. */
549     if (!cancel_flag) {
550 
551         /* Parse out the 'new event' fields. */
552         psf = tvb_get_guint8(tvb, offset) & 0x40;
553         df = tvb_get_guint8(tvb, offset) & 0x20;
554         sif = tvb_get_guint8(tvb, offset) & 0x10;
555 
556         proto_tree_add_bitmask_list(si_tree, tvb, offset, 1, new_event_fields, ENC_BIG_ENDIAN);
557         offset++;
558 
559         /* Parse out the program-level splice fields. */
560         if (psf && !sif) {
561             min_length += 1;
562             if (tvb_len < min_length)
563                 return offset;
564 
565             tsf = tvb_get_bits8(tvb, offset * 8, 1);
566             proto_tree_add_subtree(si_tree, tvb, offset, tsf ? 5 : 1, 0, &st_tree, "Program Splice Time");
567             proto_tree_add_item(st_tree, hf_splice_time_specified_flag, tvb, offset, 1, ENC_BIG_ENDIAN);
568             proto_tree_add_item(st_tree, hf_splice_time_reserved, tvb, offset, 1, ENC_BIG_ENDIAN);
569 
570             /* If a time is specified, display it too. */
571             if (tsf) {
572                 min_length += 4;
573                 if (tvb_len < min_length)
574                     return offset;
575 
576                 proto_tree_add_item(st_tree, hf_splice_time_pts_time, tvb, offset, 5, ENC_BIG_ENDIAN);
577                 offset += 4;
578             }
579             offset++;
580         }
581 
582         /* For component-level splices, parse the component table. */
583         if (!psf) {
584             min_length += 1;
585             if (tvb_len < min_length)
586                 return offset;
587 
588             component_count = tvb_get_guint8(tvb, offset);
589             proto_tree_add_item(si_tree, hf_component_count, tvb, offset, 1, ENC_BIG_ENDIAN);
590             offset++;
591 
592             min_length += component_count * (sif ? 1 : 2);
593             if (tvb_len < min_length)
594                 return offset;
595 
596             /* Dissect each splice component. */
597             for (component = 0; component < component_count; ++component) {
598                 dissected_length = dissect_component(
599                     tvb_new_subset_remaining(tvb, offset),
600                     pinfo, si_tree, sif, component);
601 
602                 /* Propagate failures. */
603                 if (dissected_length < 1)
604                     return offset;
605                 offset += dissected_length;
606             }
607         }
608 
609         /* If present, parse out the duration field. */
610         if (df) {
611             min_length += 5;
612             if (tvb_len < min_length)
613                 return offset;
614 
615             proto_tree_add_item(si_tree, hf_break_duration_auto_return, tvb, offset, 1, ENC_BIG_ENDIAN);
616             proto_tree_add_item(si_tree, hf_break_duration_reserved, tvb, offset, 1, ENC_BIG_ENDIAN);
617             proto_tree_add_item(si_tree, hf_break_duration_duration, tvb, offset, 5, ENC_BIG_ENDIAN);
618             offset += 5;
619         }
620 
621         /* Parse the UPID and avails fields. */
622         proto_tree_add_item(si_tree, hf_unique_program_id, tvb, offset, 2, ENC_BIG_ENDIAN);
623         offset += 2;
624 
625         proto_tree_add_item(si_tree, hf_avail_num, tvb, offset, 1, ENC_BIG_ENDIAN);
626         offset++;
627 
628         proto_tree_add_item(si_tree, hf_avails_expected, tvb, offset, 1, ENC_BIG_ENDIAN);
629         offset++;
630     }
631 
632     return offset;
633 }
634 
635 void
proto_register_scte35_splice_insert(void)636 proto_register_scte35_splice_insert(void)
637 {
638     static hf_register_info hf[] = {
639         {&hf_splice_insert_event_id,
640          {"Event ID", "scte35_si.event_id", FT_UINT32, BASE_HEX,
641              NULL, 0, NULL, HFILL}},
642         {&hf_splice_cancel_indicator,
643          {"Cancelled", "scte35_si.cancelled", FT_BOOLEAN, 8,
644              NULL, 0x80, NULL, HFILL}},
645         {&hf_reserved0,
646          {"Reserved", "scte35_si.reserved0", FT_UINT8, 1,
647              NULL, 0x7F, NULL, HFILL}},
648         {&hf_out_of_network_indicator,
649          {"Out of Network", "scte35_si.out_of_net", FT_BOOLEAN, 8,
650              NULL, 0x80, NULL, HFILL}},
651         {&hf_program_splice_flag,
652          {"Program Splice Point", "scte35_si.psf", FT_BOOLEAN, 8,
653              NULL, 0x40, NULL, HFILL}},
654         {&hf_duration_flag,
655          {"Duration Present", "scte35_si.duration_flag", FT_BOOLEAN, 8,
656              NULL, 0x20, NULL, HFILL}},
657         {&hf_splice_immediate_flag,
658          {"Splice Immediate", "scte35_si.splice_immediate", FT_BOOLEAN, 8,
659              NULL, 0x10, NULL, HFILL}},
660         {&hf_reserved1,
661          {"Reserved", "scte35_si.reserved1", FT_UINT8, 1,
662              NULL, 0x0f, NULL, HFILL}},
663         {&hf_splice_time_specified_flag,
664          {"Time Specified", "scte35_si.splice_time.time_specified", FT_BOOLEAN,
665              8, NULL, 0x80, NULL, HFILL}},
666         {&hf_splice_time_reserved,
667          {"Reserved", "scte35_si.splice_time.reserved", FT_UINT8, 1,
668              NULL, 0x7E, NULL, HFILL}},
669         {&hf_splice_time_pts_time,
670          {"PTS Time", "scte35_si.splice_time.pts", FT_UINT64, 5,
671              NULL, G_GUINT64_CONSTANT(0x1FFFFFFFF), NULL, HFILL}},
672         {&hf_component_count,
673          {"Component Count", "scte35_si.component_count", FT_UINT8, BASE_DEC,
674              NULL, 0, NULL, HFILL}},
675         {&hf_component_tag,
676          {"Component Tag", "scte35_si.component.tag", FT_UINT8, BASE_HEX,
677              NULL, 0, NULL, HFILL}},
678         {&hf_component_splice_time_tsf,
679          {"Time Specified", "scte35_si.component.time_specified", FT_BOOLEAN, 8,
680              NULL, 0x80, NULL, HFILL}},
681         {&hf_component_splice_time_reserved,
682          {"Reserved", "scte35_si.component.reserved", FT_UINT8, 1,
683              NULL, 0x7E, NULL, HFILL}},
684         {&hf_component_splice_time_pts_time,
685          {"PTS Time", "scte35_si.component.pts", FT_UINT64, 5,
686              NULL, G_GUINT64_CONSTANT(0x1FFFFFFFF), NULL, HFILL}},
687         {&hf_break_duration_auto_return,
688          {"Auto Return", "scte35_si.break.auto_return", FT_BOOLEAN, 8,
689              NULL, 0x80, NULL, HFILL}},
690         {&hf_break_duration_reserved,
691          {"Reserved", "scte35_si.break.reserved", FT_UINT8, 1,
692              NULL, 0x7E, NULL, HFILL}},
693         {&hf_break_duration_duration,
694          {"Duration", "scte35_si.break.duration", FT_UINT64, 5,
695              NULL, G_GUINT64_CONSTANT(0x1FFFFFFFF), NULL, HFILL}},
696         {&hf_unique_program_id,
697          {"Unique Program ID", "scte35_si.upid", FT_UINT16, BASE_HEX,
698              NULL, 0, NULL, HFILL}},
699         {&hf_avail_num,
700          {"Avail Number", "scte35_si.avail", FT_UINT8, BASE_DEC,
701              NULL, 0, NULL, HFILL}},
702         {&hf_avails_expected,
703          {"Avails Expected", "scte35_si.avails_expected", FT_UINT8, BASE_DEC,
704              NULL, 0, NULL, HFILL}},
705     };
706 
707     static gint *ett[] = {
708         &ett_scte35_splice_insert,
709     };
710 
711     proto_scte35_si = proto_register_protocol("SCTE-35 Splice Insert", "SCTE35 SI", "scte35_si");
712 
713     proto_register_subtree_array(ett, array_length(ett));
714     proto_register_field_array(proto_scte35_si, hf, array_length(hf));
715 }
716 
717 void
proto_reg_handoff_scte35_splice_insert(void)718 proto_reg_handoff_scte35_splice_insert(void)
719 {
720     dissector_handle_t scte35_si_handle;
721 
722     /* Create a splice_insert dissector, and hook it into SCTE35 parsing. */
723     scte35_si_handle = create_dissector_handle(dissect_scte35_splice_insert, proto_scte35_si);
724     dissector_add_uint("scte35.splice_command_type", SCTE35_CMD_SPLICE_INSERT, scte35_si_handle);
725 }
726 
727 
728 /* scte35 splice_schedule dissector */
729 static int
dissect_scte35_splice_schedule(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)730 dissect_scte35_splice_schedule(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
731 {
732     gint tvb_len, min_length = 1;
733     guint8 splice_count, cancel_flag, psf, df, component_count;
734     gint component, splice;
735     gint offset = 0, splice_length;
736     proto_item *ti;
737     proto_tree *ss_tree, *sp_tree, *component_tree;
738 
739     static int * const splice_event_flags[] = {
740         &hf_splice_out_of_network,
741         &hf_splice_program_splice_flag,
742         &hf_splice_duration_flag,
743         &hf_splice_reserved1,
744         NULL
745     };
746 
747     /* Check with no optional subfields */
748     tvb_len = (gint)tvb_reported_length(tvb);
749     if (tvb_len < min_length)
750         return 0;
751 
752     /* Set up headers in the packet list */
753     splice_count = tvb_get_guint8(tvb, 0);
754     min_length += splice_count * 5;
755     if (tvb_len < min_length)
756         return 0;
757 
758     col_add_fstr(pinfo->cinfo, COL_INFO, "Splice Schedule (%d splices)", splice_count);
759 
760     /* Create the root of the dissection */
761     ti = proto_tree_add_item(tree, proto_scte35_splice_schedule, tvb, 0, -1, ENC_NA);
762     ss_tree = proto_item_add_subtree(ti, ett_scte35_splice_schedule);
763 
764     /* Header fields for splice_schedule() message */
765     proto_tree_add_item(ss_tree, hf_splice_count, tvb, offset, 1, ENC_NA);
766     offset++;
767 
768     /* Process each splice. */
769     for (splice = 0; splice < splice_count; ++splice) {
770         cancel_flag = tvb_get_bits8(tvb, offset * 8 + 32, 1);
771         psf = cancel_flag ? 0 : tvb_get_bits8(tvb, offset * 8 + 41, 1);
772         df = cancel_flag ? 0 : tvb_get_bits8(tvb, offset * 8 + 42, 1);
773         component_count = cancel_flag ? 0 : (psf ? 0 : tvb_get_guint8(tvb, offset + 6));
774 
775         splice_length = 5;
776         if (!cancel_flag)
777             splice_length += 4 + 1;
778         if (!cancel_flag && psf)
779             splice_length += 4;
780         if (!cancel_flag && !psf)
781             splice_length += 1 + 5 * component_count;
782         if (!cancel_flag && df)
783             splice_length += 5;
784 
785         /* Add a subtree for the splice. */
786         proto_tree_add_subtree_format(
787             ss_tree, tvb, offset, splice_length, splice, &sp_tree,
788             "Splice %d", splice);
789 
790         /* Show the splice header. */
791         proto_tree_add_item(ss_tree, hf_splice_event_id, tvb, offset, 4, ENC_BIG_ENDIAN);
792         offset += 4;
793 
794         proto_tree_add_item(ss_tree, hf_splice_event_cancel_indicator, tvb,
795                             offset, 1, ENC_BIG_ENDIAN);
796         proto_tree_add_item(ss_tree, hf_splice_reserved0, tvb, offset, 1, ENC_BIG_ENDIAN);
797         offset++;
798 
799         if (!cancel_flag) {
800             min_length += 5;
801             if (tvb_len < min_length)
802                 return offset;
803 
804             df = tvb_get_bits8(tvb, offset * 8 + 2, 1);
805 
806             /* Parse out the splice event flags. */
807             proto_tree_add_bitmask_list(ss_tree, tvb, offset, 1, splice_event_flags, ENC_BIG_ENDIAN);
808             offset++;
809 
810             min_length += (psf ? 4 : 1);
811             if (tvb_len < min_length)
812                 return offset;
813 
814             if (psf) {
815                 proto_tree_add_item(ss_tree, hf_splice_utc_splice_time, tvb,
816                                     offset, 4, ENC_BIG_ENDIAN);
817                 offset += 4;
818             } else {
819                 component_count = tvb_get_guint8(tvb, offset);
820                 proto_tree_add_item(ss_tree, hf_splice_component_count, tvb, offset, 1, ENC_NA);
821                 offset++;
822 
823                 min_length += 5 * component_count;
824                 if (tvb_len < min_length)
825                     return offset;
826 
827                 /* Parse out each component stream. */
828                 for (component = 0; component < component_count; ++component) {
829                     proto_tree_add_subtree_format(sp_tree, tvb, offset, 5, component, &component_tree,
830                         "Component %d", component);
831                     proto_tree_add_item(component_tree, hf_splice_component_tag, tvb,
832                         offset, 1, ENC_NA);
833                     offset++;
834 
835                     proto_tree_add_item(component_tree, hf_splice_component_utc_splice_time, tvb,
836                         offset, 4, ENC_NA);
837                     offset += 4;
838                 }
839             }
840 
841             /* Parse out break duration, if present. */
842             if (df) {
843                 min_length += 5;
844                 if (tvb_len < min_length)
845                     return offset;
846 
847                 proto_tree_add_item(ss_tree, hf_splice_break_duration_auto_return, tvb,
848                     offset, 1, ENC_BIG_ENDIAN);
849                 proto_tree_add_item(ss_tree, hf_splice_break_duration_reserved, tvb,
850                     offset, 1, ENC_BIG_ENDIAN);
851                 proto_tree_add_item(ss_tree, hf_splice_break_duration_duration, tvb,
852                     offset, 5, ENC_BIG_ENDIAN);
853                 offset += 5;
854             }
855         }
856 
857         proto_tree_add_item(ss_tree, hf_splice_unique_program_id, tvb, offset, 2, ENC_BIG_ENDIAN);
858         offset += 2;
859 
860         proto_tree_add_item(ss_tree, hf_splice_avail_num, tvb, offset, 1, ENC_BIG_ENDIAN);
861         offset++;
862 
863         proto_tree_add_item(ss_tree, hf_splice_avails_expected, tvb, offset, 1, ENC_BIG_ENDIAN);
864         offset++;
865     }
866 
867     return offset;
868 }
869 
870 void
proto_register_scte35_splice_schedule(void)871 proto_register_scte35_splice_schedule(void)
872 {
873     static hf_register_info hf[] = {
874         {&hf_splice_count,
875          {"Splice Count", "scte35_splice_schedule.splice_count",
876              FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL}},
877         {&hf_splice_event_id,
878          {"Event ID", "scte35_splice_schedule.splice.event_id",
879              FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL}},
880         {&hf_splice_event_cancel_indicator,
881          {"Event Cancel Indicator", "scte35_splice_schedule.splice.event_cancel_indicator",
882              FT_BOOLEAN, 8, NULL, 0x80, NULL, HFILL}},
883         {&hf_splice_reserved0,
884          {"Reserved", "scte35_splice_schedule.splice.reserved0",
885              FT_UINT8, BASE_HEX, NULL, 0x7F, NULL, HFILL}},
886         {&hf_splice_out_of_network,
887          {"Out of Network Indicator", "scte35_splice_schedule.splice.out_of_network_indicator",
888              FT_BOOLEAN, 8, NULL, 0x80, NULL, HFILL}},
889         {&hf_splice_program_splice_flag,
890          {"Program Splice Flag", "scte35_splice_schedule.splice.program_splice_flag",
891              FT_BOOLEAN, 8, NULL, 0x40, NULL, HFILL}},
892         {&hf_splice_duration_flag,
893          {"Duration Flag", "scte35_splice_schedule.splice.duration_flag",
894              FT_BOOLEAN, 8, NULL, 0x20, NULL, HFILL}},
895         {&hf_splice_reserved1,
896          {"Reserved", "scte35_splice_schedule.splice.reserved1",
897              FT_UINT8, BASE_HEX, NULL, 0x1F, NULL, HFILL}},
898         {&hf_splice_utc_splice_time,
899          {"UTC Splice Time", "scte35_splice_schedule.splice.utc_splice_time",
900              FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL}},
901         {&hf_splice_component_count,
902          {"Component Count", "scte35_splice_schedule.splice.component_count",
903              FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL}},
904         {&hf_splice_component_tag,
905          {"Component Tag", "scte35_splice_schedule.splice.component.tag",
906              FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL}},
907         {&hf_splice_component_utc_splice_time,
908          {"UTC Splice Time", "scte35_splice_schedule.splice.component.utc_splice_time",
909              FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL}},
910         {&hf_splice_break_duration_auto_return,
911          {"Auto Return", "scte35_splice_schedule.splice.break_duration.auto_return",
912              FT_BOOLEAN, 8, NULL, 0x80, NULL, HFILL}},
913         {&hf_splice_break_duration_reserved,
914          {"Reserved", "scte35_splice_schedule.splice.break_duration.reserved",
915              FT_UINT8, BASE_HEX, NULL, 0x7E, NULL, HFILL}},
916         {&hf_splice_break_duration_duration,
917          {"Duration", "scte35_splice_schedule.splice.break_duration.duration",
918              FT_UINT64, BASE_DEC, NULL, G_GUINT64_CONSTANT(0x1FFFFFFFF), NULL, HFILL}},
919         {&hf_splice_unique_program_id,
920          {"Unique Program ID", "scte35_splice_schedule.splice.unique_program_id",
921              FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL}},
922         {&hf_splice_avail_num,
923          {"Avail Number", "scte35_splice_schedule.splice.avail_num",
924              FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL}},
925         {&hf_splice_avails_expected,
926          {"Avails Expected", "scte35_splice_schedule.splice.avails_expected",
927              FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL}},
928     };
929 
930     static gint *ett[] = {
931         &ett_scte35_splice_schedule,
932     };
933 
934     proto_scte35_splice_schedule = proto_register_protocol("SCTE-35 Splice Schedule", "SCTE35 SS", "scte35_splice_schedule");
935 
936     proto_register_subtree_array(ett, array_length(ett));
937     proto_register_field_array(proto_scte35_splice_schedule, hf, array_length(hf));
938 }
939 
940 void
proto_reg_handoff_scte35_splice_schedule(void)941 proto_reg_handoff_scte35_splice_schedule(void)
942 {
943     dissector_handle_t dissector;
944 
945     dissector = create_dissector_handle(dissect_scte35_splice_schedule, proto_scte35_splice_schedule);
946     dissector_add_uint("scte35.splice_command_type", SCTE35_CMD_SPLICE_SCHEDULE, dissector);
947 }
948 
949 
950 /* core scte35 splice_info_section dissector */
951 static int
dissect_scte35_avail_descriptor(tvbuff_t * tvb,packet_info * pinfo _U_,proto_tree * tree)952 dissect_scte35_avail_descriptor(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
953 {
954     gint offset = 0;
955     gint tvb_len;
956 
957     /* Check length. */
958     tvb_len = (gint)tvb_reported_length(tvb);
959     if (tvb_len < 4)
960         return 0;
961 
962     /* Show the field. */
963     proto_tree_add_item(tree, hf_descriptor_provider_avail_id, tvb, offset, 4, ENC_NA);
964     offset += 4;
965 
966     return offset;
967 }
968 
969 static int
dissect_scte35_dtmf_descriptor(tvbuff_t * tvb,packet_info * pinfo _U_,proto_tree * tree)970 dissect_scte35_dtmf_descriptor(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
971 {
972     gint offset = 0;
973     gint tvb_len, min_length = 2;
974     guint8 dtmf_count;
975 
976     /* Check length. */
977     tvb_len = (gint)tvb_reported_length(tvb);
978     if (tvb_len < min_length)
979         return 0;
980 
981     dtmf_count = tvb_get_bits8(tvb, (offset+1)* 8, 3);
982 
983     /* Check length with DTMF string too. */
984     min_length += dtmf_count;
985     if (tvb_len < min_length)
986         return 0;
987 
988     /* Describe header. */
989     proto_tree_add_item(tree, hf_descriptor_preroll, tvb, offset, 1, ENC_NA);
990     offset++;
991 
992     proto_tree_add_item(tree, hf_descriptor_dtmf_count, tvb, offset, 1, ENC_NA);
993     proto_tree_add_item(tree, hf_descriptor_dtmf_reserved, tvb, offset, 1, ENC_NA);
994     offset++;
995 
996     /* Show the DTMF string field. */
997     proto_tree_add_item(tree, hf_descriptor_dtmf, tvb,
998                         offset, dtmf_count, ENC_NA | ENC_ASCII);
999 
1000     offset += dtmf_count;
1001     return offset;
1002 }
1003 
1004 static int
dissect_scte35_component(tvbuff_t * tvb,packet_info * pinfo _U_,proto_tree * tree,int idx)1005 dissect_scte35_component(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int idx) {
1006     gint offset = 0;
1007     proto_tree *subtree;
1008 
1009     /* Create the subtree. */
1010     proto_tree_add_subtree_format(tree, tvb, offset, 6, idx, &subtree, "Component %d", idx);
1011 
1012     /* Display the component fields. */
1013     proto_tree_add_item(subtree, hf_descriptor_component_tag, tvb,
1014                         offset, 1, ENC_NA);
1015     offset++;
1016 
1017     proto_tree_add_item(subtree, hf_descriptor_component_reserved, tvb,
1018                         offset, 1, ENC_NA);
1019     proto_tree_add_item(subtree, hf_descriptor_component_pts_offset, tvb,
1020                         offset, 5, ENC_BIG_ENDIAN);
1021     offset += 5;
1022 
1023     return offset;
1024 }
1025 
1026 static int
dissect_scte35_segmentation_descriptor(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree)1027 dissect_scte35_segmentation_descriptor(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1028 {
1029     gint offset = 0, dissected_length = 0, component;
1030     guint8 cancel_indicator, psf, sdf, dnr, component_count, upid_length;
1031 
1032     /* Parse the common header */
1033     proto_tree_add_item(tree, hf_descriptor_event_id, tvb, offset, 4, ENC_BIG_ENDIAN);
1034     offset += 4;
1035 
1036     cancel_indicator = tvb_get_bits8(tvb, offset * 8, 1);
1037     proto_tree_add_item(tree, hf_descriptor_cancel_indicator, tvb,
1038                         offset, 1, ENC_NA);
1039     proto_tree_add_item(tree, hf_descriptor_reserved0, tvb,
1040                         offset, 1, ENC_NA);
1041     offset++;
1042 
1043     /* Parse fields for new segmentation events. */
1044     if (!cancel_indicator) {
1045         psf = tvb_get_bits8(tvb, offset * 8, 1);
1046         sdf = tvb_get_bits8(tvb, offset * 8 + 1, 1);
1047         dnr = tvb_get_bits8(tvb, offset * 8 + 2, 1);
1048         proto_tree_add_item(tree, hf_descriptor_psf, tvb, offset, 1, ENC_NA);
1049         proto_tree_add_item(tree, hf_descriptor_segmentation_duration_flag,
1050             tvb, offset, 1, ENC_NA);
1051         proto_tree_add_item(tree, hf_descriptor_delivery_not_restricted_flag,
1052             tvb, offset, 1, ENC_NA);
1053 
1054         /* Parse delivery flags */
1055         if (dnr) {
1056             proto_tree_add_item(tree, hf_descriptor_reserved1, tvb, offset, 1, ENC_NA);
1057         } else {
1058             proto_tree_add_item(tree, hf_descriptor_web_delivery_allowed_flag,
1059                                 tvb, offset, 1, ENC_NA);
1060             proto_tree_add_item(tree, hf_descriptor_no_regional_blackout_flag,
1061                                 tvb, offset, 1, ENC_NA);
1062             proto_tree_add_item(tree, hf_descriptor_archive_allow_flag,
1063                                 tvb, offset, 1, ENC_NA);
1064             proto_tree_add_item(tree, hf_descriptor_device_restrictions,
1065                                 tvb, offset, 1, ENC_NA);
1066         }
1067         offset++;
1068 
1069         /* Parse component segmentation offsets if not switched as a program. */
1070         if (!psf) {
1071             component_count = tvb_get_guint8(tvb, offset);
1072             proto_tree_add_item(tree, hf_descriptor_component_count, tvb,
1073                                 offset, 1, ENC_NA);
1074             offset++;
1075 
1076             /* Parse each component */
1077             for (component = 0; component < component_count; ++component) {
1078                 dissected_length = dissect_scte35_component(
1079                         tvb_new_subset_length(tvb, offset, 6),
1080                         pinfo, tree, component);
1081 
1082                 /* Propagate errors. */
1083                 if (dissected_length < 1)
1084                     return dissected_length;
1085                 offset += dissected_length;
1086             }
1087         }
1088 
1089         /* Parse segementation duration if present. */
1090         if (sdf) {
1091             proto_tree_add_item(tree, hf_descriptor_segmentation_duration, tvb,
1092                                 offset, 5, ENC_BIG_ENDIAN);
1093             offset += 5;
1094         }
1095 
1096         /* Parse UPID. */
1097         proto_tree_add_item(tree, hf_descriptor_segmentation_upid_type, tvb,
1098                             offset, 1, ENC_NA);
1099         offset++;
1100 
1101         upid_length = tvb_get_guint8(tvb, offset);
1102         proto_tree_add_item(tree, hf_descriptor_segmentation_upid_length, tvb,
1103                             offset, 1, ENC_NA);
1104         offset++;
1105 
1106         /* Only show non-empty UPIDs. */
1107         if (upid_length) {
1108             proto_tree_add_item(tree, hf_descriptor_segmentation_upid, tvb,
1109                                 offset, upid_length, ENC_NA | ENC_ASCII);
1110             offset += upid_length;
1111         }
1112 
1113         /* Parse Segment counts. */
1114         proto_tree_add_item(tree, hf_descriptor_segmentation_type_id, tvb, offset, 1, ENC_NA);
1115         offset++;
1116 
1117         proto_tree_add_item(tree, hf_descriptor_segment_num, tvb, offset, 1, ENC_NA);
1118         offset++;
1119 
1120         proto_tree_add_item(tree, hf_descriptor_segments_expected, tvb, offset, 1, ENC_NA);
1121         offset++;
1122     }
1123 
1124     return offset;
1125 }
1126 
1127 static int
dissect_scte35_splice_descriptor(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,int idx)1128 dissect_scte35_splice_descriptor(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int idx)
1129 {
1130     proto_tree *subtree;
1131     tvbuff_t *descriptor_tvb;
1132     gint offset = 0, dissected_length = 0;
1133     guint8 tag, length = 0;
1134 
1135     /* Create the subtree header for the descriptor. */
1136     tag = tvb_get_guint8(tvb, offset);
1137     length = tvb_get_guint8(tvb, offset + 1);
1138     proto_tree_add_subtree_format(
1139             tree, tvb, offset, length + 2, idx, &subtree,
1140             "Descriptor %d (0x%02x)", idx, tag);
1141 
1142     /* Parse descriptor headers */
1143     proto_tree_add_item(subtree, hf_splice_descriptor_tag, tvb, offset, 1, ENC_NA);
1144     offset++;
1145 
1146     proto_tree_add_item(subtree, hf_splice_descriptor_length, tvb, offset, 1, ENC_NA);
1147     offset++;
1148 
1149     proto_tree_add_item(subtree, hf_splice_descriptor_identifier, tvb,
1150             offset, 4, ENC_BIG_ENDIAN);
1151     offset += 4;
1152 
1153     /* Parse the specific descriptor type. */
1154     descriptor_tvb = tvb_new_subset_length(tvb, offset, length - 4);
1155     switch (tag) {
1156         case SCTE35_AVAIL_DESCRIPTOR:
1157             dissected_length = dissect_scte35_avail_descriptor(descriptor_tvb, pinfo, subtree);
1158             break;
1159 
1160         case SCTE35_DTMF_DESCRIPTOR:
1161             dissected_length = dissect_scte35_dtmf_descriptor(descriptor_tvb, pinfo, subtree);
1162             break;
1163 
1164         case SCTE35_SEGMENTATION_DESCRIPTOR:
1165             dissected_length = dissect_scte35_segmentation_descriptor(descriptor_tvb, pinfo, subtree);
1166             break;
1167 
1168         default:
1169             /* Just trust the descriptor_length field. */
1170             dissected_length = length - 4;
1171     }
1172 
1173     /* Propagate errors. */
1174     if (dissected_length < 1)
1175         return dissected_length;
1176 
1177     offset += dissected_length;
1178     return offset;
1179 }
1180 
1181 static int
dissect_scte35_splice_info(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)1182 dissect_scte35_splice_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
1183 {
1184     gint tvb_len, min_length = SCTE35_SI_MIN_LEN, dissected_length = 0;
1185     guint8 table_id, encrypted_packet, command_type;
1186     guint16 command_length, descriptor_loop_length, i;
1187 
1188     proto_item *ti;
1189     proto_tree *splice_info_tree;
1190     gint offset = 0, descriptor_offset = 0;
1191     tvbuff_t *command_tvb;
1192 
1193     static int * const section_flags[] = {
1194         &hf_section_syntax_indicator,
1195         &hf_private_indicator,
1196         &hf_reserved,
1197         &hf_section_length,
1198         NULL
1199     };
1200 
1201     static int * const encrypt_flags[] = {
1202         &hf_encrypted_packet,
1203         &hf_encryption_algorithm,
1204         &hf_pts_adjustment,
1205         NULL
1206     };
1207 
1208     tvb_len = (gint)tvb_reported_length(tvb);
1209     if (tvb_len < min_length)
1210         return 0;
1211 
1212     /* Pre-fetch a few fields in the message. */
1213     table_id = tvb_get_guint8(tvb, offset);
1214     encrypted_packet = tvb_get_guint8(tvb, offset + 4) & 0x80;
1215     command_type = tvb_get_guint8(tvb, offset + 13);
1216     command_length = tvb_get_ntohs(tvb, offset + 11) & 0xFFF;
1217 
1218     /* Check for excessive length before indexing past the command. */
1219     min_length += command_length;
1220     if (tvb_len < min_length)
1221         return 0;
1222 
1223     /* Determine length of descriptors. */
1224     descriptor_loop_length = tvb_get_ntohs(tvb, 14 + command_length);
1225     min_length += descriptor_loop_length;
1226     if (tvb_len < min_length)
1227         return 0;
1228 
1229     /* Check for excessive length before parsing the remainder of the packet. */
1230     if (encrypted_packet)
1231         min_length += 4;
1232 
1233     if (tvb_len < min_length)
1234         return 0;
1235 
1236     /* Set up headers in the packet list */
1237     col_set_str(pinfo->cinfo, COL_PROTOCOL, "SCTE-35");
1238     col_add_fstr(pinfo->cinfo, COL_INFO, "Table 0x%02x", table_id);
1239 
1240     /* Create the protocol header. */
1241     ti = proto_tree_add_item(tree, proto_scte35, tvb, 0, -1, ENC_NA);
1242     splice_info_tree = proto_item_add_subtree(ti, ett_scte35_splice_info_section);
1243 
1244     /* Explain the root fields. */
1245     proto_tree_add_item(splice_info_tree, hf_table_id, tvb, offset, 1, ENC_BIG_ENDIAN);
1246     offset++;
1247 
1248     proto_tree_add_bitmask_list(splice_info_tree, tvb, offset, 2, section_flags, ENC_BIG_ENDIAN);
1249     offset += 2;
1250 
1251     proto_tree_add_item(splice_info_tree, hf_protocol_version, tvb, offset, 1, ENC_BIG_ENDIAN);
1252     offset++;
1253 
1254     /* 7 bits of flags, 33 bits of PTS */
1255     proto_tree_add_bitmask_list(splice_info_tree, tvb, offset, 5, encrypt_flags, ENC_BIG_ENDIAN);
1256     offset += 5;
1257 
1258     proto_tree_add_item(splice_info_tree, hf_cw_index, tvb, offset, 1, ENC_BIG_ENDIAN);
1259     offset++;
1260 
1261     /* Two twelve-bit fields */
1262     proto_tree_add_item(splice_info_tree, hf_tier, tvb, offset, 2, ENC_BIG_ENDIAN);
1263     offset++;
1264 
1265     proto_tree_add_item(splice_info_tree, hf_splice_command_length, tvb, offset, 2, ENC_BIG_ENDIAN);
1266     offset += 2;
1267 
1268     proto_tree_add_item(splice_info_tree, hf_splice_command_type, tvb, offset, 1, ENC_BIG_ENDIAN);
1269     offset++;
1270 
1271     /* Extract the splice command payload for later use. */
1272     command_tvb = tvb_new_subset_length(tvb, offset, command_length);
1273     offset += command_length;
1274 
1275     /* Process the descriptor loop. */
1276     proto_tree_add_item(splice_info_tree, hf_descriptor_loop_length, tvb, offset, 2, ENC_BIG_ENDIAN);
1277     offset += 2;
1278 
1279     /* Explain each descriptor. */
1280     for (i = 0, descriptor_offset = offset;
1281          descriptor_offset < offset + descriptor_loop_length;
1282          ++i) {
1283         dissected_length = dissect_scte35_splice_descriptor( tvb_new_subset_remaining(tvb, descriptor_offset),
1284                 pinfo, splice_info_tree, i);
1285 
1286         /* Escalate failure. */
1287         if (dissected_length < 1)
1288             return offset;
1289         descriptor_offset += dissected_length;
1290     }
1291     offset += descriptor_loop_length;
1292 
1293     /* Explain the packet footer. */
1294     if (encrypted_packet) {
1295         proto_tree_add_item(splice_info_tree, hf_e_crc32, tvb, offset, 4, ENC_BIG_ENDIAN);
1296         offset += 4;
1297     }
1298     proto_tree_add_item(splice_info_tree, hf_crc32, tvb, offset, 4, ENC_BIG_ENDIAN);
1299     offset += 4;
1300 
1301     /* We've reached the end. Run a child dissector for the splice command. */
1302     dissector_try_uint_new(scte35_cmd_dissector_table, command_type, command_tvb, pinfo, tree,
1303         FALSE, NULL);
1304 
1305     return offset;
1306 }
1307 
1308 
1309 void
proto_register_scte35(void)1310 proto_register_scte35(void)
1311 {
1312     static gint *ett[] = {
1313         &ett_scte35_splice_info_section,
1314     };
1315 
1316     static hf_register_info hf[] = {
1317         /* MPEG Section Table Headers. Field members taken from mpeg-sect.c. */
1318         {&hf_table_id,
1319          {"Table ID", "scte35.tid", FT_UINT8, BASE_HEX,
1320              NULL, 0, NULL, HFILL}},
1321         {&hf_section_syntax_indicator,
1322          {"Section Syntax Identifier", "scte35.syntax_indicator", FT_BOOLEAN,
1323              16, TFS(&tfs_section_syntax_indicator), 0x8000, NULL, HFILL }},
1324         {&hf_private_indicator,
1325          {"Private Indicator", "scte35.private", FT_BOOLEAN,
1326              16, TFS(&tfs_private_indicator), 0x4000, NULL, HFILL }},
1327         {&hf_reserved,
1328          {"Reserved", "scte35.reserved", FT_UINT16, BASE_HEX,
1329              NULL, 0x3000, NULL, HFILL }},
1330         {&hf_section_length,
1331          {"Section length", "scte35.len", FT_UINT16, BASE_DEC,
1332              NULL, 0x0FFF, NULL, HFILL}},
1333 
1334         /* SCTE35-specific headers */
1335         {&hf_protocol_version,
1336          {"Protocol Version", "scte35.protocol_version", FT_UINT8, BASE_DEC,
1337              NULL, 0, NULL, HFILL}},
1338         {&hf_encrypted_packet,
1339          {"Encrypted Packet", "scte35.encrypted_packet", FT_BOOLEAN, 40,
1340              TFS(&tfs_encrypted_packet), G_GUINT64_CONSTANT(0x8000000000), NULL, HFILL}},
1341         {&hf_encryption_algorithm,
1342          {"Encryption Algorithm", "scte35.encryption_algorithm", FT_UINT40,
1343              BASE_HEX | BASE_RANGE_STRING, RVALS(rv_encryption_algorithm),
1344              G_GUINT64_CONSTANT(0x7E00000000), NULL, HFILL}},
1345         {&hf_pts_adjustment,
1346          {"PTS Adjustment", "scte35.pts_adjustment", FT_UINT40, BASE_DEC,
1347              NULL, G_GUINT64_CONSTANT(0x1FFFFFFFF), NULL, HFILL}},
1348         {&hf_cw_index,
1349          {"Control Word Index", "scte35.cw_index", FT_UINT8, BASE_HEX,
1350              NULL, 0, NULL, HFILL}},
1351         {&hf_tier,
1352          {"Authorisation Tier", "scte35.tier", FT_UINT16, BASE_DEC,
1353              NULL, 0xFFF0, NULL, HFILL}},
1354         {&hf_splice_command_length,
1355          {"Command Length", "scte35.splice_command_length", FT_UINT16, BASE_DEC,
1356              NULL, 0xFFF, NULL, HFILL}},
1357         {&hf_splice_command_type,
1358          {"Command Type", "scte35.splice_command_type", FT_UINT8,
1359              BASE_HEX | BASE_RANGE_STRING, RVALS(rv_splice_command_type),
1360              0, NULL, HFILL}},
1361 
1362         /* Splice command payload goes here via the dissector table. */
1363 
1364         /* Descriptor loop header. */
1365         {&hf_descriptor_loop_length,
1366          {"Descriptor Loop Length", "scte35.desc_len", FT_UINT16, BASE_DEC,
1367              NULL, 0, NULL, HFILL}},
1368 
1369         /* Descriptor loop entries. */
1370         {&hf_splice_descriptor_tag,
1371          {"Tag", "scte35.splice_descriptor.tag", FT_UINT8,
1372              BASE_HEX | BASE_RANGE_STRING, RVALS(rv_splice_descriptor_tag),
1373              0, NULL, HFILL}},
1374         {&hf_splice_descriptor_length,
1375          {"Length", "scte35.splice_descriptor.length", FT_UINT8, BASE_DEC,
1376              NULL, 0, NULL, HFILL}},
1377         {&hf_splice_descriptor_identifier,
1378          {"Descriptor ID", "scte35.splice_descriptor.identifier", FT_UINT32,
1379              BASE_HEX, NULL, 0, NULL, HFILL}},
1380 
1381         /* avail_descriptor */
1382         {&hf_descriptor_provider_avail_id,
1383          {"Provider Avail ID", "scte35.splice_descriptor.provider_avail_id",
1384              FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL}},
1385 
1386         /* dtmf_descriptor */
1387         {&hf_descriptor_preroll,
1388          {"Preroll", "scte35.splice_descriptor.preroll",
1389              FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL}},
1390         {&hf_descriptor_dtmf_count,
1391          {"DTMF Count", "scte35.splice_descriptor.dtmf_count",
1392              FT_UINT8, BASE_DEC, NULL, 0xE0, NULL, HFILL}},
1393         {&hf_descriptor_dtmf_reserved,
1394          {"DTMF Reserved", "scte35.splice_descriptor.dtmf_reserved",
1395              FT_UINT8, BASE_HEX, NULL, 0x1F, NULL, HFILL}},
1396         {&hf_descriptor_dtmf,
1397          {"DTMF", "scte35.splice_descriptor.dtmf",
1398              FT_STRING, 0, NULL, 0, NULL, HFILL}},
1399 
1400         /* segmentation_descriptor */
1401         {&hf_descriptor_event_id,
1402          {"Segmentation Event ID", "scte35.splice_descriptor.event_id",
1403              FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL}},
1404         {&hf_descriptor_cancel_indicator,
1405          {"Cancel Indicator", "scte35.splice_descriptor.cancel_indicator",
1406              FT_BOOLEAN, 8, TFS(&tfs_descriptor_cancel_indicator), 0x80, NULL, HFILL}},
1407         {&hf_descriptor_reserved0,
1408          {"Reserved", "scte35.splice_descriptor.reserved0",
1409              FT_UINT8, BASE_HEX, NULL, 0x7F, NULL, HFILL}},
1410         {&hf_descriptor_psf,
1411          {"Program Segmentation Flag", "scte35.splice_descriptor.psf",
1412              FT_BOOLEAN, 8, TFS(&tfs_descriptor_psf), 0x80, NULL, HFILL}},
1413         {&hf_descriptor_segmentation_duration_flag,
1414          {"Segmentation Duration Flag", "scte35.splice_descriptor.sdf",
1415              FT_BOOLEAN, 8, TFS(&tfs_descriptor_sdf), 0x40, NULL, HFILL}},
1416         {&hf_descriptor_delivery_not_restricted_flag,
1417          {"Delivery not Restricted", "scte35.splice_descriptor.dnr",
1418              FT_BOOLEAN, 8, TFS(&tfs_descriptor_dnr), 0x20, NULL, HFILL}},
1419         {&hf_descriptor_web_delivery_allowed_flag,
1420          {"Web Delivery Allowed", "scte35.splice_descriptor.web_delivery_allowed",
1421              FT_BOOLEAN, 8, TFS(&tfs_descriptor_web), 0x10, NULL, HFILL}},
1422         {&hf_descriptor_no_regional_blackout_flag,
1423          {"No Regional Blackout", "scte35.splice_descriptor.no_regional_blackout",
1424              FT_BOOLEAN, 8, TFS(&tfs_descriptor_blackout), 0x08, NULL, HFILL}},
1425         {&hf_descriptor_archive_allow_flag,
1426          {"Archive Allowed", "scte35.splice_descriptor.archive_allowed",
1427              FT_BOOLEAN, 8, TFS(&tfs_descriptor_archive), 0x04, NULL, HFILL}},
1428         {&hf_descriptor_device_restrictions,
1429          {"Device Restrictions", "scte35.splice_descriptor.device_restrictions",
1430              FT_UINT8, BASE_HEX | BASE_RANGE_STRING,
1431              RVALS(scte35_device_restrictions), 0x03, NULL, HFILL}},
1432         {&hf_descriptor_reserved1,
1433          {"Reserved", "scte35.splice_descriptor.reserved1",
1434              FT_UINT8, BASE_HEX, NULL, 0x1F, NULL, HFILL}},
1435         {&hf_descriptor_component_count,
1436          {"Component Count", "scte35.splice_descriptor.component_count",
1437              FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL}},
1438         {&hf_descriptor_component_tag,
1439          {"Component Tag", "scte35.splice_descriptor.component.tag",
1440              FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL}},
1441         {&hf_descriptor_component_reserved,
1442          {"Reserved", "scte35.splice_descriptor.component.reserved",
1443              FT_UINT8, BASE_HEX, NULL, 0xFE, NULL, HFILL}},
1444         {&hf_descriptor_component_pts_offset,
1445          {"PTS Offset", "scte35.splice_descriptor.component.pts_offset",
1446              FT_UINT64, BASE_DEC, NULL, 0x1FFFFFFFF, NULL, HFILL}},
1447         {&hf_descriptor_segmentation_duration,
1448          {"Segmentation Duration", "scte35.splice_descriptor.segmentation_duration",
1449              FT_UINT64, BASE_DEC, NULL, 0xFFFFFFFFFF, NULL, HFILL}},
1450         {&hf_descriptor_segmentation_upid_type,
1451          {"UPID Type", "scte35.splice_descriptor.upid_type",
1452              FT_UINT8, BASE_HEX | BASE_RANGE_STRING,
1453              RVALS(scte35_segmentation_upid_type), 0, NULL, HFILL}},
1454         {&hf_descriptor_segmentation_upid_length,
1455          {"UPID Length", "scte35.splice_descriptor.upid_length",
1456              FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL}},
1457         {&hf_descriptor_segmentation_upid,
1458          {"UPID", "scte35.splice_descriptor.upid",
1459              FT_STRING, 0, NULL, 0, NULL, HFILL}},
1460         {&hf_descriptor_segmentation_type_id,
1461          {"Segmentation Type", "scte35.splice_descriptor.segmentation_type_id",
1462              FT_UINT8, BASE_HEX | BASE_RANGE_STRING,
1463              RVALS(scte35_segmentation_type_id), 0, NULL, HFILL}},
1464         {&hf_descriptor_segment_num,
1465          {"Segment Number", "scte35.splice_descriptor.segment_num",
1466              FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL}},
1467         {&hf_descriptor_segments_expected,
1468          {"Segments Expected", "scte35.splice_descriptor.segments_expected",
1469              FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL}},
1470 
1471         /* Optional alignment padding, encrypted CRC32 suffix. */
1472         {&hf_e_crc32,
1473          {"Encrypted CRC32", "scte35.ecrc32", FT_UINT32, BASE_HEX,
1474              NULL, 0, NULL, HFILL}},
1475 
1476         /* MPEG Section table CRC suffix */
1477         {&hf_crc32,
1478          {"CRC32", "scte35.crc", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL}},
1479     };
1480 
1481     /* Allocate a protocol number. */
1482     proto_scte35 = proto_register_protocol(
1483         "SCTE-35 Splice Information",  /* name */
1484         "SCTE 35",                     /* short name */
1485         "scte35"                       /* abbreviation */
1486         );
1487     scte35_handle = register_dissector("scte35", dissect_scte35_splice_info, proto_scte35);
1488 
1489     /* Register groups and fields. */
1490     proto_register_subtree_array(ett, array_length(ett));
1491     proto_register_field_array(proto_scte35, hf, array_length(hf));
1492 
1493     /* Allow other protocols to discriminate against the splice command type
1494      * to further dissect the payload.
1495      */
1496     scte35_cmd_dissector_table = register_dissector_table(
1497         "scte35.splice_command_type", "SCTE-35 Command", proto_scte35, FT_UINT8,
1498         BASE_HEX);
1499 }
1500 
1501 void
proto_reg_handoff_scte35(void)1502 proto_reg_handoff_scte35(void)
1503 {
1504     /* Invoke the splice_info_section parser for a section table with ID 0xFC */
1505     dissector_add_uint("mpeg_sect.tid", SCTE35_TABLE_ID, scte35_handle);
1506 }
1507 
1508 /*
1509  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
1510  *
1511  * Local variables:
1512  * c-basic-offset: 4
1513  * tab-width: 8
1514  * indent-tabs-mode: nil
1515  * End:
1516  *
1517  * vi: set shiftwidth=4 tabstop=8 expandtab:
1518  * :indentSize=4:tabSize=8:noTabs=true:
1519  */
1520