summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/demuxers/Makefile.am15
-rw-r--r--src/demuxers/demux_idcin.c104
-rw-r--r--src/demuxers/demux_wc3movie.c229
3 files changed, 202 insertions, 146 deletions
diff --git a/src/demuxers/Makefile.am b/src/demuxers/Makefile.am
index e50ce5977..7792faae6 100644
--- a/src/demuxers/Makefile.am
+++ b/src/demuxers/Makefile.am
@@ -39,7 +39,8 @@ lib_LTLIBRARIES = $(ogg_module) $(asf_module) $(qt_modules) xineplug_dmx_avi.la\
xineplug_dmx_mpeg_elem.la xineplug_dmx_mpeg_audio.la \
xineplug_dmx_film.la xineplug_dmx_wav.la \
xineplug_dmx_aiff.la xineplug_dmx_voc.la \
- xineplug_dmx_snd.la
+ xineplug_dmx_snd.la xineplug_dmx_idcin.la \
+ xineplug_dmx_wc3movie.la
xineplug_dmx_ogg_la_SOURCES = demux_ogg.c
xineplug_dmx_ogg_la_LIBADD = $(OGG_LIBS) $(VORBIS_LIBS)\
@@ -106,13 +107,13 @@ xineplug_dmx_wav_la_SOURCES = demux_wav.c
xineplug_dmx_wav_la_LIBADD = $(top_builddir)/src/xine-engine/libxine.la
xineplug_dmx_wav_la_LDFLAGS = -avoid-version -module
-#xineplug_dmx_idcin_la_SOURCES = demux_idcin.c
-#xineplug_dmx_idcin_la_LIBADD = $(top_builddir)/src/xine-engine/libxine.la
-#xineplug_dmx_idcin_la_LDFLAGS = -avoid-version -module
+xineplug_dmx_idcin_la_SOURCES = demux_idcin.c
+xineplug_dmx_idcin_la_LIBADD = $(top_builddir)/src/xine-engine/libxine.la
+xineplug_dmx_idcin_la_LDFLAGS = -avoid-version -module
-#xineplug_dmx_wc3movie_la_SOURCES = demux_wc3movie.c
-#xineplug_dmx_wc3movie_la_LIBADD = $(top_builddir)/src/xine-engine/libxine.la
-#xineplug_dmx_wc3movie_la_LDFLAGS = -avoid-version -module
+xineplug_dmx_wc3movie_la_SOURCES = demux_wc3movie.c
+xineplug_dmx_wc3movie_la_LIBADD = $(top_builddir)/src/xine-engine/libxine.la
+xineplug_dmx_wc3movie_la_LDFLAGS = -avoid-version -module
#xineplug_dmx_vqa_la_SOURCES = demux_vqa.c
#xineplug_dmx_vqa_la_LIBADD = $(top_builddir)/src/xine-engine/libxine.la
diff --git a/src/demuxers/demux_idcin.c b/src/demuxers/demux_idcin.c
index b8f9e328b..8106842cf 100644
--- a/src/demuxers/demux_idcin.c
+++ b/src/demuxers/demux_idcin.c
@@ -63,7 +63,7 @@
* - if any bytes exceed 63, do not shift the bytes at all before
* transmitting them to the video decoder
*
- * $Id: demux_idcin.c,v 1.10 2002/09/10 15:07:14 mroi Exp $
+ * $Id: demux_idcin.c,v 1.11 2002/09/21 19:18:37 tmmm Exp $
*/
#ifdef HAVE_CONFIG_H
@@ -311,6 +311,59 @@ static void *demux_idcin_loop (void *this_gen) {
return NULL;
}
+static int load_idcin_and_send_headers(demux_idcin_t *this) {
+
+ unsigned char header[IDCIN_HEADER_SIZE];
+
+ pthread_mutex_lock(&this->mutex);
+
+ this->video_fifo = this->xine->video_fifo;
+ this->audio_fifo = this->xine->audio_fifo;
+
+ this->status = DEMUX_OK;
+
+ this->input->seek(this->input, 0, SEEK_SET);
+ if (this->input->read(this->input, header, IDCIN_HEADER_SIZE) !=
+ IDCIN_HEADER_SIZE) {
+ this->status = DEMUX_FINISHED;
+ pthread_mutex_unlock(&this->mutex);
+ return DEMUX_CANNOT_HANDLE;
+ }
+
+ this->video_width = LE_32(&header[0]);
+ this->video_height = LE_32(&header[4]);
+ this->audio_sample_rate = LE_32(&header[8]);
+ this->audio_bytes_per_sample = LE_32(&header[12]);
+ this->audio_channels = LE_32(&header[16]);
+ this->filesize = this->input->get_length(this->input);
+
+ /* read the Huffman table */
+ if (this->input->read(this->input, this->huffman_table,
+ HUFFMAN_TABLE_SIZE) != HUFFMAN_TABLE_SIZE) {
+ this->status = DEMUX_FINISHED;
+ pthread_mutex_unlock(&this->mutex);
+ return DEMUX_CANNOT_HANDLE;
+ }
+
+ /* load stream information */
+ this->xine->stream_info[XINE_STREAM_INFO_VIDEO_WIDTH] =
+ this->video_width;
+ this->xine->stream_info[XINE_STREAM_INFO_VIDEO_HEIGHT] =
+ this->video_height;
+ this->xine->stream_info[XINE_STREAM_INFO_AUDIO_CHANNELS] =
+ this->audio_channels;
+ this->xine->stream_info[XINE_STREAM_INFO_AUDIO_SAMPLERATE] =
+ this->audio_sample_rate;
+ this->xine->stream_info[XINE_STREAM_INFO_AUDIO_BITS] =
+ this->audio_bytes_per_sample * 8;
+
+ xine_demux_control_headers_done (this->xine);
+
+ pthread_mutex_unlock (&this->mutex);
+
+ return DEMUX_CAN_HANDLE;
+}
+
static int demux_idcin_open(demux_plugin_t *this_gen,
input_plugin_t *input, int stage) {
@@ -365,8 +418,9 @@ static int demux_idcin_open(demux_plugin_t *this_gen,
if (current_value > 2)
return DEMUX_CANNOT_HANDLE;
- /* if execution got this far, qualify it as a valid Id CIN file */
- return DEMUX_CAN_HANDLE;
+ /* if execution got this far, qualify it as a valid Id CIN file
+ * and load it */
+ return load_idcin_and_send_headers(this);
}
break;
@@ -389,10 +443,8 @@ static int demux_idcin_open(demux_plugin_t *this_gen,
while(*m == ' ' || *m == '\t') m++;
- if(!strcasecmp((suffix + 1), m)) {
- this->input = input;
- return DEMUX_CAN_HANDLE;
- }
+ if(!strcasecmp((suffix + 1), m))
+ return load_idcin_and_send_headers(this);
}
return DEMUX_CANNOT_HANDLE;
}
@@ -407,52 +459,24 @@ static int demux_idcin_open(demux_plugin_t *this_gen,
}
static int demux_idcin_start (demux_plugin_t *this_gen,
- fifo_buffer_t *video_fifo,
- fifo_buffer_t *audio_fifo,
off_t start_pos, int start_time) {
demux_idcin_t *this = (demux_idcin_t *) this_gen;
buf_element_t *buf;
int err;
- char header[IDCIN_HEADER_SIZE];
pthread_mutex_lock(&this->mutex);
/* if thread is not running, initialize demuxer */
if (!this->thread_running) {
- this->video_fifo = video_fifo;
- this->audio_fifo = audio_fifo;
-
- this->input->seek(this->input, 0, SEEK_SET);
- if (this->input->read(this->input, header, IDCIN_HEADER_SIZE) !=
- IDCIN_HEADER_SIZE) {
- this->status = DEMUX_FINISHED;
- pthread_mutex_unlock(&this->mutex);
- return DEMUX_FINISHED;
- }
-
- this->video_width = LE_32(&header[0]);
- this->video_height = LE_32(&header[4]);
- this->audio_sample_rate = LE_32(&header[8]);
- this->audio_bytes_per_sample = LE_32(&header[12]);
- this->audio_channels = LE_32(&header[16]);
- this->filesize = this->input->get_length(this->input);
-
- /* read the Huffman table */
- if (this->input->read(this->input, this->huffman_table,
- HUFFMAN_TABLE_SIZE) != HUFFMAN_TABLE_SIZE) {
- this->status = DEMUX_FINISHED;
- pthread_mutex_unlock(&this->mutex);
- return DEMUX_FINISHED;
- }
/* print vital stats */
- xine_log (this->xine, XINE_LOG_FORMAT,
+ xine_log (this->xine, XINE_LOG_MSG,
_("demux_idcin: Id CIN file, video is %dx%d, 14 frames/sec\n"),
this->video_width,
this->video_height);
if (this->audio_channels)
- xine_log (this->xine, XINE_LOG_FORMAT,
+ xine_log (this->xine, XINE_LOG_MSG,
_("demux_idcin: %d-bit, %d Hz %s PCM audio\n"),
this->audio_bytes_per_sample * 8,
this->audio_sample_rate,
@@ -564,7 +588,7 @@ static void demux_idcin_stop (demux_plugin_t *this_gen) {
xine_demux_control_end(this->xine, BUF_FLAG_END_USER);
}
-static void demux_idcin_close (demux_plugin_t *this) {
+static void demux_idcin_dispose (demux_plugin_t *this) {
free(this);
}
@@ -603,7 +627,7 @@ static void *init_demuxer_plugin(xine_t *xine, void *data) {
this->demux_plugin.start = demux_idcin_start;
this->demux_plugin.seek = demux_idcin_seek;
this->demux_plugin.stop = demux_idcin_stop;
- this->demux_plugin.close = demux_idcin_close;
+ this->demux_plugin.dispose = demux_idcin_dispose;
this->demux_plugin.get_status = demux_idcin_get_status;
this->demux_plugin.get_identifier = demux_idcin_get_id;
this->demux_plugin.get_stream_length = demux_idcin_get_stream_length;
@@ -621,6 +645,6 @@ static void *init_demuxer_plugin(xine_t *xine, void *data) {
plugin_info_t xine_plugin_info[] = {
/* type, API, "name", version, special_info, init_function */
- { PLUGIN_DEMUX, 10, "idcin", XINE_VERSION_CODE, NULL, init_demuxer_plugin },
+ { PLUGIN_DEMUX, 11, "idcin", XINE_VERSION_CODE, NULL, init_demuxer_plugin },
{ PLUGIN_NONE, 0, "", 0, NULL, NULL }
};
diff --git a/src/demuxers/demux_wc3movie.c b/src/demuxers/demux_wc3movie.c
index 513592dca..fb9eb9889 100644
--- a/src/demuxers/demux_wc3movie.c
+++ b/src/demuxers/demux_wc3movie.c
@@ -22,7 +22,7 @@
* For more information on the MVE file format, visit:
* http://www.pcisys.net/~melanson/codecs/
*
- * $Id: demux_wc3movie.c,v 1.7 2002/09/10 15:07:14 mroi Exp $
+ * $Id: demux_wc3movie.c,v 1.8 2002/09/21 19:18:37 tmmm Exp $
*/
#ifdef HAVE_CONFIG_H
@@ -68,6 +68,8 @@
#define PALETTE_CHUNK_SIZE (PALETTE_SIZE * 3)
#define WC3_FRAMERATE 15
#define WC3_PTS_INC (90000 / 15)
+#define WC3_USUAL_WIDTH 320
+#define WC3_USUAL_HEIGHT 165
#define PREAMBLE_SIZE 8
@@ -95,6 +97,8 @@ typedef struct {
unsigned int fps;
unsigned int frame_pts_inc;
+ unsigned int video_width;
+ unsigned int video_height;
xine_waveformatex wave;
@@ -193,7 +197,7 @@ static void *demux_mve_loop (void *this_gen) {
palette_number = LE_32(&preamble[0]);
if (palette_number >= this->number_of_palettes) {
- xine_log(this->xine, XINE_LOG_FORMAT,
+ xine_log(this->xine, XINE_LOG_MSG,
_("demux_wc3movie: SHOT chunk referenced invalid palette (%d >= %d)\n"),
palette_number, this->number_of_palettes);
this->status = DEMUX_FINISHED;
@@ -323,6 +327,117 @@ static void *demux_mve_loop (void *this_gen) {
return NULL;
}
+static int load_mve_and_send_headers(demux_mve_t *this) {
+
+ unsigned char preamble[PREAMBLE_SIZE];
+ unsigned char disk_palette[PALETTE_CHUNK_SIZE];
+ int i, j;
+ unsigned char r, g, b;
+ int temp;
+
+ pthread_mutex_lock(&this->mutex);
+
+ this->video_fifo = this->xine->video_fifo;
+ this->audio_fifo = this->xine->audio_fifo;
+
+ this->status = DEMUX_OK;
+
+ /* these are the frame dimensions unless others are found */
+ this->video_width = WC3_USUAL_WIDTH;
+ this->video_height = WC3_USUAL_HEIGHT;
+
+ /* load the number of palettes, the only interesting piece of information
+ * in the _PC_ chunk; take it for granted that it will always appear at
+ * position 0x1C */
+ this->input->seek(this->input, 0x1C, SEEK_SET);
+ if (this->input->read(this->input, preamble, 4) != 4) {
+ this->status = DEMUX_FINISHED;
+ pthread_mutex_unlock(&this->mutex);
+ return DEMUX_CANNOT_HANDLE;
+ }
+ this->number_of_palettes = LE_32(&preamble[0]);
+
+ /* skip the SOND chunk */
+ this->input->seek(this->input, 12, SEEK_CUR);
+
+ /* load the palette chunks */
+ this->palettes = xine_xmalloc(this->number_of_palettes * PALETTE_SIZE *
+ sizeof(palette_entry_t));
+ for (i = 0; i < this->number_of_palettes; i++) {
+ /* make sure there was a valid palette chunk preamble */
+ if (this->input->read(this->input, preamble, PREAMBLE_SIZE) !=
+ PREAMBLE_SIZE) {
+ this->status = DEMUX_FINISHED;
+ pthread_mutex_unlock(&this->mutex);
+ return DEMUX_CANNOT_HANDLE;
+ }
+
+ if ((BE_32(&preamble[0]) != PALT_TAG) ||
+ (BE_32(&preamble[4]) != PALETTE_CHUNK_SIZE)) {
+ xine_log(this->xine, XINE_LOG_MSG,
+ _("demux_wc3movie: There was a problem while loading palette chunks\n"));
+ this->status = DEMUX_FINISHED;
+ pthread_mutex_unlock(&this->mutex);
+ return DEMUX_CANNOT_HANDLE;
+ }
+
+ /* load the palette chunk */
+ if (this->input->read(this->input, disk_palette, PALETTE_CHUNK_SIZE) !=
+ PALETTE_CHUNK_SIZE) {
+ this->status = DEMUX_FINISHED;
+ pthread_mutex_unlock(&this->mutex);
+ return DEMUX_CANNOT_HANDLE;
+ }
+
+ /* convert and store the palette */
+ for (j = 0; j < PALETTE_SIZE; j++) {
+ r = disk_palette[j * 3 + 0];
+ g = disk_palette[j * 3 + 1];
+ b = disk_palette[j * 3 + 2];
+ /* rotate each component left by 2 */
+ temp = r << 2; r = (temp & 0xff) | (temp >> 8);
+ r = wc3_pal_lookup[r];
+ temp = g << 2; g = (temp & 0xff) | (temp >> 8);
+ g = wc3_pal_lookup[g];
+ temp = b << 2; b = (temp & 0xff) | (temp >> 8);
+ b = wc3_pal_lookup[b];
+ this->palettes[i * 256 + j].r = r;
+ this->palettes[i * 256 + j].g = g;
+ this->palettes[i * 256 + j].b = b;
+ }
+ }
+
+ /* next should be the INDX chunk; skip it */
+ if (this->input->read(this->input, preamble, PREAMBLE_SIZE) !=
+ PREAMBLE_SIZE) {
+ this->status = DEMUX_FINISHED;
+ pthread_mutex_unlock(&this->mutex);
+ return DEMUX_CANNOT_HANDLE;
+ }
+ this->input->seek(this->input, BE_32(&preamble[4]), SEEK_CUR);
+
+ /* note the data start offset right after the INDEX chunks */
+ this->data_start = this->input->get_current_pos(this->input);
+
+ this->data_size = this->input->get_length(this->input) - this->data_start;
+
+ /* load stream information */
+ this->xine->stream_info[XINE_STREAM_INFO_VIDEO_WIDTH] = this->video_width;
+ this->xine->stream_info[XINE_STREAM_INFO_VIDEO_HEIGHT] = this->video_height;
+ this->xine->stream_info[XINE_STREAM_INFO_AUDIO_CHANNELS] =
+ this->wave.nChannels;
+ this->xine->stream_info[XINE_STREAM_INFO_AUDIO_SAMPLERATE] =
+ this->wave.nSamplesPerSec;
+ this->xine->stream_info[XINE_STREAM_INFO_AUDIO_BITS] =
+ this->wave.wBitsPerSample;
+
+ xine_demux_control_headers_done (this->xine);
+
+ pthread_mutex_unlock (&this->mutex);
+
+ return DEMUX_CAN_HANDLE;
+}
+
static int demux_mve_open(demux_plugin_t *this_gen, input_plugin_t *input,
int stage) {
demux_mve_t *this = (demux_mve_t *) this_gen;
@@ -342,7 +457,7 @@ static int demux_mve_open(demux_plugin_t *this_gen, input_plugin_t *input,
if ((BE_32(&header[0]) == FORM_TAG) &&
(BE_32(&header[8]) == MOVE_TAG) &&
(BE_32(&header[12]) == PC_TAG))
- return DEMUX_CAN_HANDLE;
+ return load_mve_and_send_headers(this);
return DEMUX_CANNOT_HANDLE;
}
@@ -367,10 +482,8 @@ static int demux_mve_open(demux_plugin_t *this_gen, input_plugin_t *input,
while(*m == ' ' || *m == '\t') m++;
- if(!strcasecmp((suffix + 1), m)) {
- this->input = input;
- return DEMUX_CAN_HANDLE;
- }
+ if(!strcasecmp((suffix + 1), m))
+ return load_mve_and_send_headers(this);
}
return DEMUX_CANNOT_HANDLE;
}
@@ -386,98 +499,14 @@ static int demux_mve_open(demux_plugin_t *this_gen, input_plugin_t *input,
}
static int demux_mve_start (demux_plugin_t *this_gen,
- fifo_buffer_t *video_fifo,
- fifo_buffer_t *audio_fifo,
off_t start_pos, int start_time) {
demux_mve_t *this = (demux_mve_t *) this_gen;
buf_element_t *buf;
int err;
- unsigned char preamble[PREAMBLE_SIZE];
- unsigned char disk_palette[PALETTE_CHUNK_SIZE];
- int i, j;
- unsigned char r, g, b;
- int temp;
/* if thread is not running, initialize demuxer */
if (!this->thread_running) {
- this->video_fifo = video_fifo;
- this->audio_fifo = audio_fifo;
-
- /* load the number of palettes, the only interesting piece of information
- * in the _PC_ chunk; take it for granted that it will always appear at
- * position 0x1C */
- this->input->seek(this->input, 0x1C, SEEK_SET);
- if (this->input->read(this->input, preamble, 4) != 4) {
- this->status = DEMUX_FINISHED;
- pthread_mutex_unlock(&this->mutex);
- return DEMUX_FINISHED;
- }
- this->number_of_palettes = LE_32(&preamble[0]);
-
- /* skip the SOND chunk */
- this->input->seek(this->input, 12, SEEK_CUR);
-
- /* load the palette chunks */
- this->palettes = xine_xmalloc(this->number_of_palettes * PALETTE_SIZE *
- sizeof(palette_entry_t));
- for (i = 0; i < this->number_of_palettes; i++) {
- /* make sure there was a valid palette chunk preamble */
- if (this->input->read(this->input, preamble, PREAMBLE_SIZE) !=
- PREAMBLE_SIZE) {
- this->status = DEMUX_FINISHED;
- pthread_mutex_unlock(&this->mutex);
- return DEMUX_FINISHED;
- }
-
- if ((BE_32(&preamble[0]) != PALT_TAG) ||
- (BE_32(&preamble[4]) != PALETTE_CHUNK_SIZE)) {
- xine_log(this->xine, XINE_LOG_FORMAT,
- _("demux_wc3movie: There was a problem while loading palette chunks\n"));
- this->status = DEMUX_FINISHED;
- pthread_mutex_unlock(&this->mutex);
- return DEMUX_FINISHED;
- }
-
- /* load the palette chunk */
- if (this->input->read(this->input, disk_palette, PALETTE_CHUNK_SIZE) !=
- PALETTE_CHUNK_SIZE) {
- this->status = DEMUX_FINISHED;
- pthread_mutex_unlock(&this->mutex);
- return DEMUX_FINISHED;
- }
-
- /* convert and store the palette */
- for (j = 0; j < PALETTE_SIZE; j++) {
- r = disk_palette[j * 3 + 0];
- g = disk_palette[j * 3 + 1];
- b = disk_palette[j * 3 + 2];
- /* rotate each component left by 2 */
- temp = r << 2; r = (temp & 0xff) | (temp >> 8);
- r = wc3_pal_lookup[r];
- temp = g << 2; g = (temp & 0xff) | (temp >> 8);
- g = wc3_pal_lookup[g];
- temp = b << 2; b = (temp & 0xff) | (temp >> 8);
- b = wc3_pal_lookup[b];
- this->palettes[i * 256 + j].r = r;
- this->palettes[i * 256 + j].g = g;
- this->palettes[i * 256 + j].b = b;
- }
- }
-
- /* next should be the INDX chunk; skip it */
- if (this->input->read(this->input, preamble, PREAMBLE_SIZE) !=
- PREAMBLE_SIZE) {
- this->status = DEMUX_FINISHED;
- pthread_mutex_unlock(&this->mutex);
- return DEMUX_FINISHED;
- }
- this->input->seek(this->input, BE_32(&preamble[4]), SEEK_CUR);
-
- /* note the data start offset right after the INDEX chunks */
- this->data_start = this->input->get_current_pos(this->input);
-
- this->data_size = this->input->get_length(this->input) - this->data_start;
/* send start buffers */
xine_demux_control_start(this->xine);
@@ -490,11 +519,13 @@ static int demux_mve_start (demux_plugin_t *this_gen,
buf->decoder_flags = BUF_FLAG_HEADER;
buf->decoder_info[0] = 0;
buf->decoder_info[1] = WC3_PTS_INC; /* initial video_step */
- /* You know what? Since WC3 movies are hardcoded to a resolution of
- * 320x165 and the video decoder knows that, I won't even bother
- * transmitting the video resolution. (Ordinarily, the video
- * resolution is transmitted to the video decoder at this stage.) */
- buf->size = 0;
+ /* really be a rebel: No structure at all, just put the video width
+ * and height straight into the buffer, BE_16 format */
+ buf->content[0] = (this->video_width >> 8) & 0xFF;
+ buf->content[1] = (this->video_width >> 0) & 0xFF;
+ buf->content[2] = (this->video_height >> 8) & 0xFF;
+ buf->content[3] = (this->video_height >> 0) & 0xFF;
+ buf->size = 4;
buf->type = BUF_VIDEO_WC3;
this->video_fifo->put (this->video_fifo, buf);
@@ -564,7 +595,7 @@ static void demux_mve_stop (demux_plugin_t *this_gen) {
xine_demux_control_end(this->xine, BUF_FLAG_END_USER);
}
-static void demux_mve_close (demux_plugin_t *this_gen) {
+static void demux_mve_dispose (demux_plugin_t *this_gen) {
demux_mve_t *this = (demux_mve_t *) this_gen;
free(this->palettes);
@@ -607,7 +638,7 @@ static void *init_demuxer_plugin(xine_t *xine, void *data) {
this->demux_plugin.start = demux_mve_start;
this->demux_plugin.seek = demux_mve_seek;
this->demux_plugin.stop = demux_mve_stop;
- this->demux_plugin.close = demux_mve_close;
+ this->demux_plugin.dispose = demux_mve_dispose;
this->demux_plugin.get_status = demux_mve_get_status;
this->demux_plugin.get_identifier = demux_mve_get_id;
this->demux_plugin.get_stream_length = demux_mve_get_stream_length;
@@ -625,6 +656,6 @@ static void *init_demuxer_plugin(xine_t *xine, void *data) {
plugin_info_t xine_plugin_info[] = {
/* type, API, "name", version, special_info, init_function */
- { PLUGIN_DEMUX, 10, "wc3movie", XINE_VERSION_CODE, NULL, init_demuxer_plugin },
+ { PLUGIN_DEMUX, 11, "wc3movie", XINE_VERSION_CODE, NULL, init_demuxer_plugin },
{ PLUGIN_NONE, 0, "", 0, NULL, NULL }
};