summaryrefslogtreecommitdiff
path: root/src/demuxers/demux_real.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/demuxers/demux_real.c')
-rw-r--r--src/demuxers/demux_real.c237
1 files changed, 105 insertions, 132 deletions
diff --git a/src/demuxers/demux_real.c b/src/demuxers/demux_real.c
index 11b0dbf38..8f6ce0611 100644
--- a/src/demuxers/demux_real.c
+++ b/src/demuxers/demux_real.c
@@ -15,7 +15,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
/*
@@ -30,8 +30,6 @@
* (C) Alex Beregszaszi <alex@naxine.org>
*
* Based on FFmpeg's libav/rm.c.
- *
- * $Id: demux_real.c,v 1.113 2007/02/20 00:34:56 dgp85 Exp $
*/
#ifdef HAVE_CONFIG_H
@@ -51,10 +49,10 @@
#define LOG
*/
-#include "xine_internal.h"
-#include "xineutils.h"
-#include "compat.h"
-#include "demux.h"
+#include <xine/xine_internal.h>
+#include <xine/xineutils.h>
+#include <xine/compat.h>
+#include <xine/demux.h>
#include "bswap.h"
#define FOURCC_TAG BE_FOURCC
@@ -194,11 +192,11 @@ static void real_parse_index(demux_real_t *this) {
}
/* Check chunk is actually an index chunk */
- if(BE_32(&index_chunk_header[0]) == INDX_TAG) {
+ if(_X_BE_32(&index_chunk_header[0]) == INDX_TAG) {
unsigned short version;
/* Check version */
- version = BE_16(&index_chunk_header[8]);
+ version = _X_BE_16(&index_chunk_header[8]);
if(version != 0) {
xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG,
"demux_real: unknown object version in INDX: 0x%04x\n", version);
@@ -206,9 +204,9 @@ static void real_parse_index(demux_real_t *this) {
}
/* Read data from header */
- entries = BE_32(&index_chunk_header[10]);
- stream_num = BE_16(&index_chunk_header[14]);
- next_index_chunk = BE_32(&index_chunk_header[16]);
+ entries = _X_BE_32(&index_chunk_header[10]);
+ stream_num = _X_BE_16(&index_chunk_header[14]);
+ next_index_chunk = _X_BE_32(&index_chunk_header[16]);
/* Find which stream this index is for */
index = NULL;
@@ -234,7 +232,7 @@ static void real_parse_index(demux_real_t *this) {
if(index && entries) {
/* Allocate memory for index */
- *index = xine_xmalloc(entries * sizeof(real_index_entry_t));
+ *index = xine_xcalloc(entries, sizeof(real_index_entry_t));
/* Read index */
for(i = 0; i < entries; i++) {
@@ -246,9 +244,9 @@ static void real_parse_index(demux_real_t *this) {
break;
}
- (*index)[i].timestamp = BE_32(&index_record[2]);
- (*index)[i].offset = BE_32(&index_record[6]);
- (*index)[i].packetno = BE_32(&index_record[10]);
+ (*index)[i].timestamp = _X_BE_32(&index_record[2]);
+ (*index)[i].offset = _X_BE_32(&index_record[6]);
+ (*index)[i].packetno = _X_BE_32(&index_record[10]);
}
} else {
lprintf("unused index chunk with %d entries for stream num %d\n",
@@ -267,29 +265,23 @@ static void real_parse_index(demux_real_t *this) {
static mdpr_t *real_parse_mdpr(const char *data) {
mdpr_t *mdpr=malloc(sizeof(mdpr_t));
- mdpr->stream_number=BE_16(&data[2]);
- mdpr->max_bit_rate=BE_32(&data[4]);
- mdpr->avg_bit_rate=BE_32(&data[8]);
- mdpr->max_packet_size=BE_32(&data[12]);
- mdpr->avg_packet_size=BE_32(&data[16]);
- mdpr->start_time=BE_32(&data[20]);
- mdpr->preroll=BE_32(&data[24]);
- mdpr->duration=BE_32(&data[28]);
+ mdpr->stream_number=_X_BE_16(&data[2]);
+ mdpr->max_bit_rate=_X_BE_32(&data[4]);
+ mdpr->avg_bit_rate=_X_BE_32(&data[8]);
+ mdpr->max_packet_size=_X_BE_32(&data[12]);
+ mdpr->avg_packet_size=_X_BE_32(&data[16]);
+ mdpr->start_time=_X_BE_32(&data[20]);
+ mdpr->preroll=_X_BE_32(&data[24]);
+ mdpr->duration=_X_BE_32(&data[28]);
mdpr->stream_name_size=data[32];
- mdpr->stream_name=malloc(sizeof(char)*(mdpr->stream_name_size+1));
- memcpy(mdpr->stream_name, &data[33], mdpr->stream_name_size);
- mdpr->stream_name[(int)mdpr->stream_name_size]=0;
+ mdpr->stream_name=xine_memdup0(&data[33], mdpr->stream_name_size);
mdpr->mime_type_size=data[33+mdpr->stream_name_size];
- mdpr->mime_type=malloc(sizeof(char)*(mdpr->mime_type_size+1));
- memcpy(mdpr->mime_type, &data[34+mdpr->stream_name_size], mdpr->mime_type_size);
- mdpr->mime_type[(int)mdpr->mime_type_size]=0;
+ mdpr->mime_type=xine_memdup0(&data[34+mdpr->stream_name_size], mdpr->mime_type_size);
- mdpr->type_specific_len=BE_32(&data[34+mdpr->stream_name_size+mdpr->mime_type_size]);
- mdpr->type_specific_data=malloc(sizeof(char)*(mdpr->type_specific_len));
- memcpy(mdpr->type_specific_data,
- &data[38+mdpr->stream_name_size+mdpr->mime_type_size], mdpr->type_specific_len);
+ mdpr->type_specific_len=_X_BE_32(&data[34+mdpr->stream_name_size+mdpr->mime_type_size]);
+ mdpr->type_specific_data=xine_memdup(&data[38+mdpr->stream_name_size+mdpr->mime_type_size], mdpr->type_specific_len);
lprintf("MDPR: stream number: %i\n", mdpr->stream_number);
lprintf("MDPR: maximal bit rate: %i\n", mdpr->max_bit_rate);
@@ -345,14 +337,14 @@ static void real_parse_headers (demux_real_t *this) {
return;
}
- if (BE_32(signature) != RMF_TAG) {
+ if (_X_BE_32(signature) != RMF_TAG) {
this->status = DEMUX_FINISHED;
lprintf ("signature not found '%.4s'\n", signature);
return;
}
/* skip to the start of the first chunk and start traversing */
- chunk_size = BE_32(&signature[4]);
+ chunk_size = _X_BE_32(&signature[4]);
this->input->seek(this->input, chunk_size-8, SEEK_CUR);
/* iterate through chunks and gather information until the first DATA
@@ -364,8 +356,8 @@ static void real_parse_headers (demux_real_t *this) {
this->status = DEMUX_FINISHED;
return;
}
- chunk_type = BE_32(&preamble[0]);
- chunk_size = BE_32(&preamble[4]);
+ chunk_type = _X_BE_32(&preamble[0]);
+ chunk_size = _X_BE_32(&preamble[4]);
lprintf ("chunktype %.4s len %d\n", (char *) &chunk_type, chunk_size);
switch (chunk_type) {
@@ -383,7 +375,7 @@ static void real_parse_headers (demux_real_t *this) {
return;
}
- version = BE_16(&chunk_buffer[0]);
+ version = _X_BE_16(&chunk_buffer[0]);
if (chunk_type == PROP_TAG) {
@@ -395,10 +387,10 @@ static void real_parse_headers (demux_real_t *this) {
return;
}
- this->duration = BE_32(&chunk_buffer[22]);
- this->index_start = BE_32(&chunk_buffer[30]);
- this->data_start = BE_32(&chunk_buffer[34]);
- this->avg_bitrate = BE_32(&chunk_buffer[6]);
+ this->duration = _X_BE_32(&chunk_buffer[22]);
+ this->index_start = _X_BE_32(&chunk_buffer[30]);
+ this->data_start = _X_BE_32(&chunk_buffer[34]);
+ this->avg_bitrate = _X_BE_32(&chunk_buffer[6]);
lprintf("PROP: duration: %d ms\n", this->duration);
lprintf("PROP: index start: %"PRIX64"\n", this->index_start);
@@ -427,7 +419,7 @@ static void real_parse_headers (demux_real_t *this) {
lprintf ("parsing type specific data...\n");
- if(BE_32(mdpr->type_specific_data) == RA_TAG) {
+ if(_X_BE_32(mdpr->type_specific_data) == RA_TAG) {
int version, len;
if(this->num_audio_streams == MAX_AUDIO_STREAMS) {
@@ -436,7 +428,7 @@ static void real_parse_headers (demux_real_t *this) {
goto unknown;
}
- version = BE_16(mdpr->type_specific_data + 4);
+ version = _X_BE_16(mdpr->type_specific_data + 4);
lprintf("audio version %d detected\n", version);
@@ -444,14 +436,14 @@ static void real_parse_headers (demux_real_t *this) {
case 3:
/* Version 3 header stores fourcc after meta info - cheat by reading backwards from the
* end of the header instead of having to parse it all */
- fourcc = ME_32(mdpr->type_specific_data + mdpr->type_specific_len - 5);
+ fourcc = _X_ME_32(mdpr->type_specific_data + mdpr->type_specific_len - 5);
break;
case 4:
len = *(mdpr->type_specific_data + 56);
- fourcc = ME_32(mdpr->type_specific_data + 58 + len);
+ fourcc = _X_ME_32(mdpr->type_specific_data + 58 + len);
break;
case 5:
- fourcc = ME_32(mdpr->type_specific_data + 66);
+ fourcc = _X_ME_32(mdpr->type_specific_data + 66);
break;
default:
lprintf("unsupported audio header version %d\n", version);
@@ -467,7 +459,7 @@ static void real_parse_headers (demux_real_t *this) {
this->num_audio_streams++;
- } else if(BE_32(mdpr->type_specific_data + 4) == VIDO_TAG) {
+ } else if(_X_BE_32(mdpr->type_specific_data + 4) == VIDO_TAG) {
if(this->num_video_streams == MAX_VIDEO_STREAMS) {
xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG,
@@ -476,12 +468,12 @@ static void real_parse_headers (demux_real_t *this) {
}
lprintf ("video detected\n");
- fourcc = ME_32(mdpr->type_specific_data + 8);
+ fourcc = _X_ME_32(mdpr->type_specific_data + 8);
lprintf("fourcc = %.4s\n", (char *) &fourcc);
this->video_streams[this->num_video_streams].fourcc = fourcc;
this->video_streams[this->num_video_streams].buf_type = _x_fourcc_to_buf_video(fourcc);
- this->video_streams[this->num_video_streams].format = BE_32(mdpr->type_specific_data + 30);
+ this->video_streams[this->num_video_streams].format = _X_BE_32(mdpr->type_specific_data + 30);
this->video_streams[this->num_video_streams].index = NULL;
this->video_streams[this->num_video_streams].mdpr = mdpr;
@@ -506,28 +498,28 @@ unknown:
stream_ptr = 2;
/* load the title string */
- field_size = BE_16(&chunk_buffer[stream_ptr]);
+ field_size = _X_BE_16(&chunk_buffer[stream_ptr]);
stream_ptr += 2;
_x_meta_info_n_set(this->stream, XINE_META_INFO_TITLE,
&chunk_buffer[stream_ptr], field_size);
stream_ptr += field_size;
/* load the author string */
- field_size = BE_16(&chunk_buffer[stream_ptr]);
+ field_size = _X_BE_16(&chunk_buffer[stream_ptr]);
stream_ptr += 2;
_x_meta_info_n_set(this->stream, XINE_META_INFO_ARTIST,
&chunk_buffer[stream_ptr], field_size);
stream_ptr += field_size;
/* load the copyright string as the year */
- field_size = BE_16(&chunk_buffer[stream_ptr]);
+ field_size = _X_BE_16(&chunk_buffer[stream_ptr]);
stream_ptr += 2;
_x_meta_info_n_set(this->stream, XINE_META_INFO_YEAR,
&chunk_buffer[stream_ptr], field_size);
stream_ptr += field_size;
/* load the comment string */
- field_size = BE_16(&chunk_buffer[stream_ptr]);
+ field_size = _X_BE_16(&chunk_buffer[stream_ptr]);
stream_ptr += 2;
_x_meta_info_n_set(this->stream, XINE_META_INFO_COMMENT,
&chunk_buffer[stream_ptr], field_size);
@@ -545,7 +537,7 @@ unknown:
}
/* check version */
- version = BE_16(&data_chunk_header[0]);
+ version = _X_BE_16(&data_chunk_header[0]);
if(version != 0) {
xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG,
"demux_real: unknown object version in DATA: 0x%04x\n", version);
@@ -553,8 +545,8 @@ unknown:
return;
}
- this->current_data_chunk_packet_count = BE_32(&data_chunk_header[2]);
- this->next_data_chunk_offset = BE_32(&data_chunk_header[6]);
+ this->current_data_chunk_packet_count = _X_BE_32(&data_chunk_header[2]);
+ this->next_data_chunk_offset = _X_BE_32(&data_chunk_header[6]);
this->data_chunk_size = chunk_size;
break;
@@ -625,11 +617,11 @@ unknown:
int i, stream;
/* Check for end of the data chunk */
- if(((id = BE_32(&search_buffer[offset])) == DATA_TAG) ||
+ if(((id = _X_BE_32(&search_buffer[offset])) == DATA_TAG) ||
(id == INDX_TAG))
break;
- stream = BE_16(&search_buffer[offset + 4]);
+ stream = _X_BE_16(&search_buffer[offset + 4]);
for(i = 0; !this->video_stream && (i < this->num_video_streams); i++) {
if(stream == this->video_streams[i].mdpr->stream_number) {
@@ -645,7 +637,7 @@ unknown:
}
}
- offset += BE_16(&search_buffer[offset + 2]);
+ offset += _X_BE_16(&search_buffer[offset + 2]);
}
if(INPUT_IS_SEEKABLE(this->input))
@@ -692,7 +684,7 @@ unknown:
this->video_stream->mdpr->avg_bit_rate);
/* Allocate fragment offset table */
- this->fragment_tab = xine_xmalloc(FRAGMENT_TAB_SIZE*sizeof(uint32_t));
+ this->fragment_tab = xine_xcalloc(FRAGMENT_TAB_SIZE, sizeof(uint32_t));
this->fragment_tab_max = FRAGMENT_TAB_SIZE;
}
@@ -716,7 +708,7 @@ unknown:
* The second is the codec initialisation data found at the end of
* the type specific data for the audio stream */
if(buf->type == BUF_AUDIO_AAC) {
- int version = BE_16(mdpr->type_specific_data + 4);
+ int version = _X_BE_16(mdpr->type_specific_data + 4);
if(version != 5) {
xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG,
@@ -725,9 +717,9 @@ unknown:
goto unsupported;
}
- buf->decoder_info[1] = BE_16(mdpr->type_specific_data + 54);
- buf->decoder_info[2] = BE_16(mdpr->type_specific_data + 58);
- buf->decoder_info[3] = BE_16(mdpr->type_specific_data + 60);
+ buf->decoder_info[1] = _X_BE_16(mdpr->type_specific_data + 54);
+ buf->decoder_info[2] = _X_BE_16(mdpr->type_specific_data + 58);
+ buf->decoder_info[3] = _X_BE_16(mdpr->type_specific_data + 60);
buf->decoder_flags |= BUF_FLAG_STDHEADER;
buf->content = NULL;
@@ -740,7 +732,7 @@ unknown:
buf->type = this->audio_stream->buf_type;
buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_FRAME_END|BUF_FLAG_SPECIAL;
buf->decoder_info[1] = BUF_SPECIAL_DECODER_CONFIG;
- buf->decoder_info[2] = BE_32(mdpr->type_specific_data + 74) - 1;
+ buf->decoder_info[2] = _X_BE_32(mdpr->type_specific_data + 74) - 1;
buf->decoder_info_ptr[2] = buf->content;
buf->size = 0;
@@ -806,8 +798,27 @@ static int demux_real_parse_references( demux_real_t *this) {
lprintf("received %d bytes [%s]\n", buf_used, buf);
- for(i=0;i<buf_used;i++) {
-
+ if (!strncmp(buf,"http://",7))
+ {
+ i = 0;
+ while (buf[i])
+ {
+ j = i;
+ while (buf[i] && !isspace(buf[i]))
+ ++i; /* skip non-space */
+ len = buf[i];
+ buf[i] = 0;
+ if (strncmp (buf + j, "http://", 7) || (i - j) < 8)
+ break; /* stop at the first non-http reference */
+ lprintf("reference [%s] found\n", buf + j);
+ _x_demux_send_mrl_reference (this->stream, 0, buf + j, NULL, 0, 0);
+ buf[i] = (char) len;
+ while (buf[i] && isspace(buf[i]))
+ ++i; /* skip spaces */
+ }
+ }
+ else for (i = 0; i < buf_used; ++i)
+ {
/* "--stop--" is used to have pnm alternative for old real clients
* new real clients will stop processing the file and thus use
* rtsp protocol.
@@ -952,7 +963,7 @@ static int stream_read_char (demux_real_t *this) {
static int stream_read_word (demux_real_t *this) {
uint16_t ret;
this->input->read (this->input, (char *) &ret, 2);
- return BE_16(&ret);
+ return _X_BE_16(&ret);
}
static int demux_real_send_chunk(demux_plugin_t *this_gen) {
@@ -981,7 +992,7 @@ static int demux_real_send_chunk(demux_plugin_t *this_gen) {
}
/* Check to see if we've gone past the end of the data chunk */
- if(((id = BE_32(&header[0])) == DATA_TAG) ||
+ if(((id = _X_BE_32(&header[0])) == DATA_TAG) ||
(id == INDX_TAG)) {
lprintf("finished reading data chunk\n");
this->status = DEMUX_FINISHED;
@@ -989,7 +1000,7 @@ static int demux_real_send_chunk(demux_plugin_t *this_gen) {
}
/* check version */
- version = BE_16(&header[0]);
+ version = _X_BE_16(&header[0]);
if(version > 1) {
xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG,
"demux_real: unknown object version in data packet: 0x%04x\n", version);
@@ -998,10 +1009,10 @@ static int demux_real_send_chunk(demux_plugin_t *this_gen) {
}
/* read the packet information */
- stream = BE_16(&header[4]);
+ stream = _X_BE_16(&header[4]);
offset = this->input->get_current_pos(this->input);
- size = BE_16(&header[2]) - DATA_PACKET_HEADER_SIZE;
- timestamp= BE_32(&header[6]);
+ size = _X_BE_16(&header[2]) - DATA_PACKET_HEADER_SIZE;
+ timestamp= _X_BE_32(&header[6]);
pts = (int64_t) timestamp * 90;
/* Data packet header with version 1 contains 1 extra byte */
@@ -1282,7 +1293,7 @@ static int demux_real_send_chunk(demux_plugin_t *this_gen) {
frames = (stream_read_word(this) & 0xf0) >> 4;
/* 2 bytes per frame size */
- sizes = xine_xmalloc(frames*sizeof(int));
+ sizes = xine_xcalloc(frames, sizeof(int));
for(i = 0; i < frames; i++)
sizes[i] = stream_read_word(this);
@@ -1355,8 +1366,8 @@ discard:
return this->status;
}
lprintf ("**** found next DATA tag\n");
- this->current_data_chunk_packet_count = BE_32(&data_chunk_header[2]);
- this->next_data_chunk_offset = BE_32(&data_chunk_header[6]);
+ this->current_data_chunk_packet_count = _X_BE_32(&data_chunk_header[2]);
+ this->next_data_chunk_offset = _X_BE_32(&data_chunk_header[6]);
}
if (!this->current_data_chunk_packet_count) {
@@ -1482,18 +1493,15 @@ static void demux_real_dispose (demux_plugin_t *this_gen) {
for(i = 0; i < this->num_video_streams; i++) {
real_free_mdpr(this->video_streams[i].mdpr);
- if(this->video_streams[i].index)
- free(this->video_streams[i].index);
+ free(this->video_streams[i].index);
}
for(i = 0; i < this->num_audio_streams; i++) {
real_free_mdpr(this->audio_streams[i].mdpr);
- if(this->audio_streams[i].index)
- free(this->audio_streams[i].index);
+ free(this->audio_streams[i].index);
}
- if(this->fragment_tab)
- free(this->fragment_tab);
+ free(this->fragment_tab);
free(this);
}
@@ -1534,7 +1542,8 @@ static int real_check_stream_type(uint8_t *buf, int len)
return 1;
buf[len] = '\0';
- if( strstr(buf,"pnm://") || strstr(buf,"rtsp://") || strstr(buf,"<smil>") )
+ if( strstr(buf,"pnm://") || strstr(buf,"rtsp://") || strstr(buf,"<smil>") ||
+ !strncmp(buf,"http://",7) )
return 2;
return 0;
@@ -1564,22 +1573,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str
lprintf ("by content accepted.\n");
break;
- case METHOD_BY_EXTENSION: {
- const char *extensions, *mrl;
-
- mrl = input->get_mrl (input);
- extensions = class_gen->get_extensions (class_gen);
-
- lprintf ("by extension '%s'\n", mrl);
-
- if (!_x_demux_check_extension (mrl, extensions)) {
- return NULL;
- }
- lprintf ("by extension accepted.\n");
- }
-
- break;
-
+ case METHOD_BY_MRL:
case METHOD_EXPLICIT:
break;
@@ -1618,42 +1612,21 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str
return &this->demux_plugin;
}
-static const char *get_description (demux_class_t *this_gen) {
- return "RealMedia file demux plugin";
-}
-
-static const char *get_identifier (demux_class_t *this_gen) {
- return "Real";
-}
-
-static const char *get_extensions (demux_class_t *this_gen) {
- return "rm rmvb ram";
-}
-
-static const char *get_mimetypes (demux_class_t *this_gen) {
- return "audio/x-pn-realaudio: ra, rm, ram: Real Media file;"
- "audio/x-pn-realaudio-plugin: rpm: Real Media plugin file;"
- "audio/x-real-audio: ra, rm, ram: Real Media file;"
- "application/vnd.rn-realmedia: ra, rm, ram: Real Media file;";
-}
-
-static void class_dispose (demux_class_t *this_gen) {
- demux_real_class_t *this = (demux_real_class_t *) this_gen;
-
- free (this);
-}
-
static void *init_class (xine_t *xine, void *data) {
demux_real_class_t *this;
this = xine_xmalloc (sizeof (demux_real_class_t));
this->demux_class.open_plugin = open_plugin;
- this->demux_class.get_description = get_description;
- this->demux_class.get_identifier = get_identifier;
- this->demux_class.get_mimetypes = get_mimetypes;
- this->demux_class.get_extensions = get_extensions;
- this->demux_class.dispose = class_dispose;
+ this->demux_class.description = N_("RealMedia file demux plugin");
+ this->demux_class.identifier = "Real";
+ this->demux_class.mimetypes =
+ "audio/x-pn-realaudio: ra, rm, ram: Real Media file;"
+ "audio/x-pn-realaudio-plugin: rpm: Real Media plugin file;"
+ "audio/x-real-audio: ra, rm, ram: Real Media file;"
+ "application/vnd.rn-realmedia: ra, rm, ram: Real Media file;";
+ this->demux_class.extensions = "rm rmvb ram";
+ this->demux_class.dispose = default_demux_class_dispose;
return this;
}
@@ -1667,6 +1640,6 @@ static const demuxer_info_t demux_info_real = {
const plugin_info_t xine_plugin_info[] EXPORTED = {
/* type, API, "name", version, special_info, init_function */
- { PLUGIN_DEMUX, 26, "real", XINE_VERSION_CODE, &demux_info_real, init_class },
+ { PLUGIN_DEMUX, 27, "real", XINE_VERSION_CODE, &demux_info_real, init_class },
{ PLUGIN_NONE, 0, "", 0, NULL, NULL }
};