void process_xds_bytes (const unsigned char hi, int lo) { int is_new; if (hi>=0x01 && hi<=0x0f) { int xds_class=(hi-1)/2; // Start codes 1 and 2 are "class type" 0, 3-4 are 2, and so on. is_new=hi%2; // Start codes are even dbg_print(DMT_XDS, "XDS Start: %u.%u Is new: %d | Class: %d (%s), Used buffers: %d\n",hi,lo, is_new,xds_class, XDSclasses[xds_class], how_many_used()); int first_free_buf=-1; int matching_buf=-1; for (int i=0;i<NUM_XDS_BUFFERS;i++) { if (xds_buffers[i].in_use && xds_buffers[i].xds_class==xds_class && xds_buffers[i].xds_type==lo) { matching_buf=i; break; } if (first_free_buf==-1 && !xds_buffers[i].in_use) first_free_buf=i; } /* Here, 3 possibilities: 1) We already had a buffer for this class/type and matching_buf points to it 2) We didn't have a buffer for this class/type and first_free_buf points to an unused one 3) All buffers are full and we will have to skip this packet. */ if (matching_buf==-1 && first_free_buf==-1) { mprint ("Note: All XDS buffers full (bug or suicidal stream). Ignoring this one (%d,%d).\n",xds_class,lo); cur_xds_buffer_idx=-1; return; } cur_xds_buffer_idx=(matching_buf!=-1)? matching_buf:first_free_buf; if (is_new || !xds_buffers[cur_xds_buffer_idx].in_use) { // Whatever we had before we discard; must belong to an interrupted packet xds_buffers[cur_xds_buffer_idx].xds_class=xds_class; xds_buffers[cur_xds_buffer_idx].xds_type=lo; xds_buffers[cur_xds_buffer_idx].used_bytes=0; xds_buffers[cur_xds_buffer_idx].in_use=1; memset (xds_buffers[cur_xds_buffer_idx].bytes,0,NUM_BYTES_PER_PACKET); } if (!is_new) { // Continue codes aren't added to packet. return; } } else { // Informational: 00, or 0x20-0x7F, so 01-0x1f forbidden dbg_print(DMT_XDS, "XDS: %02X.%02X (%c, %c)\n",hi,lo,hi,lo); if ((hi>0 && hi<=0x1f) || (lo>0 && lo<=0x1f)) { mprint ("\rNote: Illegal XDS data"); return; } } if (xds_buffers[cur_xds_buffer_idx].used_bytes<=32) { // Should always happen xds_buffers[cur_xds_buffer_idx].bytes[xds_buffers[cur_xds_buffer_idx].used_bytes++]=hi; xds_buffers[cur_xds_buffer_idx].bytes[xds_buffers[cur_xds_buffer_idx].used_bytes++]=lo; xds_buffers[cur_xds_buffer_idx].bytes[xds_buffers[cur_xds_buffer_idx].used_bytes]=0; } }
void do_end_of_xds (unsigned char expected_checksum) { if (cur_xds_buffer_idx== -1 || /* Unknown buffer, or not in use (bug) */ !xds_buffers[cur_xds_buffer_idx].in_use) return; cur_xds_packet_class=xds_buffers[cur_xds_buffer_idx].xds_class; cur_xds_payload=xds_buffers[cur_xds_buffer_idx].bytes; cur_xds_payload_length=xds_buffers[cur_xds_buffer_idx].used_bytes; cur_xds_packet_type=cur_xds_payload[1]; cur_xds_payload[cur_xds_payload_length++]=0x0F; // The end byte itself, added to the packet int cs=0; for (int i=0; i<cur_xds_payload_length;i++) { cs=cs+cur_xds_payload[i]; cs=cs & 0x7f; // Keep 7 bits only int c=cur_xds_payload[i]&0x7F; dbg_print(DMT_XDS, "%02X - %c cs: %02X\n", c,(c>=0x20)?c:'?', cs); } cs=(128-cs) & 0x7F; // Convert to 2's complement & discard high-order bit dbg_print(DMT_XDS, "End of XDS. Class=%d (%s), size=%d Checksum OK: %d Used buffers: %d\n", cur_xds_packet_class,XDSclasses[cur_xds_packet_class], cur_xds_payload_length, cs==expected_checksum, how_many_used()); if (cs!=expected_checksum || cur_xds_payload_length<3) { dbg_print(DMT_XDS, "Expected checksum: %02X Calculated: %02X\n", expected_checksum, cs); clear_xds_buffer (cur_xds_buffer_idx); return; // Bad packets ignored as per specs } int was_proc=0; /* Indicated if the packet was processed. Not processed means "code to do it doesn't exist yet", not an error. */ switch (cur_xds_packet_class) { case XDS_CLASS_FUTURE: // Info on future program if (!(debug_mask & DMT_XDS)) // Don't bother processing something we don't need { was_proc=1; break; } case XDS_CLASS_CURRENT: // Info on current program was_proc = xds_do_current_and_future(); break; case XDS_CLASS_CHANNEL: was_proc = xds_do_channel(); break; case XDS_CLASS_MISC: was_proc = xds_do_misc(); break; } if (!was_proc) { mprint ("Note: We found an currently unsupported XDS packet.\n"); } clear_xds_buffer (cur_xds_buffer_idx); }
void do_end_of_xds (struct cc_subtitle *sub, struct ccx_decoders_xds_context *ctx, unsigned char expected_checksum) { int cs = 0; int i; if(!ctx) return; if (ctx->cur_xds_buffer_idx== -1 || /* Unknown buffer, or not in use (bug) */ !ctx->xds_buffers[ctx->cur_xds_buffer_idx].in_use) return; ctx->cur_xds_packet_class = ctx->xds_buffers[ctx->cur_xds_buffer_idx].xds_class; ctx->cur_xds_payload = ctx->xds_buffers[ctx->cur_xds_buffer_idx].bytes; ctx->cur_xds_payload_length=ctx->xds_buffers[ctx->cur_xds_buffer_idx].used_bytes; ctx->cur_xds_packet_type=ctx->cur_xds_payload[1]; ctx->cur_xds_payload[ctx->cur_xds_payload_length++]=0x0F; // The end byte itself, added to the packet for (i = 0; i < ctx->cur_xds_payload_length; i++) { cs=cs+ctx->cur_xds_payload[i]; cs=cs & 0x7f; // Keep 7 bits only int c=ctx->cur_xds_payload[i]&0x7F; ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "%02X - %c cs: %02X\n", c,(c>=0x20)?c:'?', cs); } cs=(128-cs) & 0x7F; // Convert to 2's complement & discard high-order bit ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "End of XDS. Class=%d (%s), size=%d Checksum OK: %d Used buffers: %d\n", ctx->cur_xds_packet_class,XDSclasses[ctx->cur_xds_packet_class], ctx->cur_xds_payload_length, cs==expected_checksum, how_many_used(ctx)); if (cs!=expected_checksum || ctx->cur_xds_payload_length<3) { ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "Expected checksum: %02X Calculated: %02X\n", expected_checksum, cs); clear_xds_buffer (ctx, ctx->cur_xds_buffer_idx); return; // Bad packets ignored as per specs } int was_proc=0; /* Indicated if the packet was processed. Not processed means "code to do it doesn't exist yet", not an error. */ if (ctx->cur_xds_packet_type & 0x40) // Bit 6 set { ctx->cur_xds_packet_class = XDS_CLASS_OUT_OF_BAND; } switch (ctx->cur_xds_packet_class) { case XDS_CLASS_FUTURE: // Info on future program if (!(ccx_common_logging.debug_mask & CCX_DMT_DECODER_XDS)) // Don't bother processing something we don't need { was_proc=1; break; } case XDS_CLASS_CURRENT: // Info on current program was_proc = xds_do_current_and_future(sub, ctx); break; case XDS_CLASS_CHANNEL: was_proc = xds_do_channel(sub, ctx); break; case XDS_CLASS_MISC: was_proc = xds_do_misc(ctx); break; case XDS_CLASS_PRIVATE: // CEA-608: // The Private Data Class is for use in any closed system for whatever that // system wishes. It shall not be defined by this standard now or in the future. was_proc = xds_do_private_data(sub, ctx); break; case XDS_CLASS_OUT_OF_BAND: ccx_common_logging.debug_ftn(CCX_DMT_DECODER_XDS, "Out-of-band data, ignored."); was_proc = 1; break; } if (!was_proc) { ccx_common_logging.log_ftn ("Note: We found a currently unsupported XDS packet.\n"); dump (CCX_DMT_DECODER_XDS,ctx->cur_xds_payload,ctx->cur_xds_payload_length,0,0); } clear_xds_buffer (ctx, ctx->cur_xds_buffer_idx); }