1
0
mirror of https://gitlab.xiph.org/xiph/icecast-server.git synced 2024-11-03 04:17:17 -05:00

Make the state-machine nature of the EBML parser more evident.

This commit is contained in:
Joseph Wallace 2015-11-21 03:12:33 -05:00
parent 15e7fc6e4a
commit 744b66c40e

View File

@ -39,6 +39,10 @@
#define EBML_HEADER_MAX_SIZE 131072 #define EBML_HEADER_MAX_SIZE 131072
#define EBML_SLICE_SIZE 4096 #define EBML_SLICE_SIZE 4096
typedef enum ebml_read_mode {
EBML_STATE_READING_HEADER = 0,
EBML_STATE_READING_CLUSTERS
} ebml_read_mode;
typedef struct ebml_client_data_st ebml_client_data_t; typedef struct ebml_client_data_st ebml_client_data_t;
@ -51,6 +55,8 @@ struct ebml_client_data_st {
struct ebml_st { struct ebml_st {
ebml_read_mode output_state;
char *cluster_id; char *cluster_id;
int cluster_start; int cluster_start;
@ -58,7 +64,6 @@ struct ebml_st {
unsigned char *input_buffer; unsigned char *input_buffer;
unsigned char *buffer; unsigned char *buffer;
int header_read;
int header_size; int header_size;
int header_position; int header_position;
int header_read_position; int header_read_position;
@ -302,6 +307,8 @@ static ebml_t *ebml_create()
ebml_t *ebml = calloc(1, sizeof(ebml_t)); ebml_t *ebml = calloc(1, sizeof(ebml_t));
ebml->output_state = EBML_STATE_READING_HEADER;
ebml->header = calloc(1, EBML_HEADER_MAX_SIZE); ebml->header = calloc(1, EBML_HEADER_MAX_SIZE);
ebml->buffer = calloc(1, EBML_SLICE_SIZE * 4); ebml->buffer = calloc(1, EBML_SLICE_SIZE * 4);
ebml->input_buffer = calloc(1, EBML_SLICE_SIZE); ebml->input_buffer = calloc(1, EBML_SLICE_SIZE);
@ -322,9 +329,20 @@ static int ebml_read_space(ebml_t *ebml)
int read_space; int read_space;
if (ebml->header_read == 1) switch (ebml->output_state) {
{ case EBML_STATE_READING_HEADER:
/* The header has previously been read */
if (ebml->header_size != 0) {
/* The header can be read */
return ebml->header_size;
} else {
/* The header's not ready yet */
return 0;
}
break;
case EBML_STATE_READING_CLUSTERS:
if (ebml->cluster_start > 0) { if (ebml->cluster_start > 0) {
/* return up until just before a new cluster starts */ /* return up until just before a new cluster starts */
read_space = ebml->cluster_start; read_space = ebml->cluster_start;
@ -337,20 +355,13 @@ static int ebml_read_space(ebml_t *ebml)
return read_space; return read_space;
} }
else
{
if (ebml->header_size != 0) {
/* The header can be read */
return ebml->header_size;
} else {
/* The header's not ready yet */
return 0;
}
}
ICECAST_LOG_ERROR("EBML: Invalid parser read state");
return 0;
} }
/* Return a chunk of the EBML/MKV/WebM stream. /* Return a chunk of the EBML/MKV/WebM stream.
* The header will be buffered until it can be returned as one chunk.
* A cluster element's opening tag will always start a new chunk. * A cluster element's opening tag will always start a new chunk.
*/ */
static int ebml_read(ebml_t *ebml, char *buffer, int len) static int ebml_read(ebml_t *ebml, char *buffer, int len)
@ -363,9 +374,35 @@ static int ebml_read(ebml_t *ebml, char *buffer, int len)
return 0; return 0;
} }
if (ebml->header_read == 1) switch (ebml->output_state) {
case EBML_STATE_READING_HEADER:
if (ebml->header_size != 0)
{ {
/* The header has previously been read */ /* Can read a chunk of the header */
read_space = ebml->header_size - ebml->header_read_position;
if (read_space >= len) {
to_read = len;
} else {
to_read = read_space;
}
memcpy(buffer, ebml->header, to_read);
ebml->header_read_position += to_read;
if (ebml->header_read_position == ebml->header_size) {
ebml->output_state = EBML_STATE_READING_CLUSTERS;
}
} else {
/* The header's not ready yet */
return 0;
}
break;
case EBML_STATE_READING_CLUSTERS:
if (ebml->cluster_start > 0) { if (ebml->cluster_start > 0) {
/* return up until just before a new cluster starts */ /* return up until just before a new cluster starts */
read_space = ebml->cluster_start; read_space = ebml->cluster_start;
@ -392,32 +429,8 @@ static int ebml_read(ebml_t *ebml, char *buffer, int len)
if (ebml->cluster_start > 0) { if (ebml->cluster_start > 0) {
ebml->cluster_start -= to_read; ebml->cluster_start -= to_read;
} }
}
else
{
if (ebml->header_size != 0)
{
/* Can read a chunk of the header */
read_space = ebml->header_size - ebml->header_read_position;
if (read_space >= len) { break;
to_read = len;
} else {
to_read = read_space;
}
memcpy(buffer, ebml->header, to_read);
ebml->header_read_position += to_read;
if (ebml->header_read_position == ebml->header_size) {
ebml->header_read = 1;
}
}
else
{
/* The header's not ready yet */
return 0;
}
} }
return to_read; return to_read;