1 /*
2  * MOC - music on console
3  * Copyright (C) 2004 Damian Pietras <daper@daper.net>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  */
11 
12 #ifdef HAVE_CONFIG_H
13 # include "config.h"
14 #endif
15 
16 #include <stdio.h>
17 #include <string.h>
18 #include <stdarg.h>
19 #include <errno.h>
20 #include <assert.h>
21 #include <ltdl.h>
22 
23 #include "common.h"
24 #include "decoder.h"
25 #include "files.h"
26 #include "log.h"
27 #include "io.h"
28 #include "compat.h"
29 #include "options.h"
30 
31 static struct plugin {
32 	char *name;
33 	lt_dlhandle handle;
34 	struct decoder *decoder;
35 } plugins[16];
36 
37 #define PLUGINS_NUM			(ARRAY_SIZE(plugins))
38 
39 static int plugins_num = 0;
40 
41 static bool have_tremor = false;
42 
43 /* This structure holds the user's decoder preferences for audio formats. */
44 struct decoder_s_preference {
45 	struct decoder_s_preference *next;    /* chain pointer */
46 #ifdef DEBUG
47 	const char *source;                   /* entry in PreferredDecoders */
48 #endif
49 	int decoders;                         /* number of decoders */
50 	int decoder_list[PLUGINS_NUM];        /* decoder indices */
51 	char *subtype;                        /* MIME subtype or NULL */
52 	char type[FLEXIBLE_ARRAY_MEMBER];     /* MIME type or filename extn */
53 };
54 typedef struct decoder_s_preference decoder_t_preference;
55 static decoder_t_preference *preferences = NULL;
56 static int default_decoder_list[PLUGINS_NUM];
57 
clean_mime_subtype(char * subtype)58 static char *clean_mime_subtype (char *subtype)
59 {
60 	char *ptr;
61 
62 	assert (subtype && subtype[0]);
63 
64 	if (!strncasecmp (subtype, "x-", 2))
65 		subtype += 2;
66 
67 	ptr = strchr (subtype, ';');
68 	if (ptr)
69 		*ptr = 0x00;
70 
71 	return subtype;
72 }
73 
74 /* Find a preference entry matching the given filename extension and/or
75  * MIME media type, or NULL. */
lookup_preference(const char * extn,const char * file,char ** mime)76 static decoder_t_preference *lookup_preference (const char *extn,
77                                                 const char *file,
78                                                 char **mime)
79 {
80 	char *type, *subtype;
81 	decoder_t_preference *result;
82 
83 	assert ((extn && extn[0]) || (file && file[0])
84 	                          || (mime && *mime && *mime[0]));
85 
86 	type = NULL;
87 	subtype = NULL;
88 	for (result = preferences; result; result = result->next) {
89 		if (!result->subtype) {
90 			if (extn && !strcasecmp (result->type, extn))
91 				break;
92 		}
93 		else {
94 
95 			if (!type) {
96 				if (mime && *mime == NULL && file && file[0]) {
97 					if (options_get_bool ("UseMimeMagic"))
98 						*mime = file_mime_type (file);
99 				}
100 				if (mime && *mime && strchr (*mime, '/'))
101 					type = xstrdup (*mime);
102 				if (type) {
103 					subtype = strchr (type, '/');
104 					*subtype++ = 0x00;
105 					subtype = clean_mime_subtype (subtype);
106 				}
107 			}
108 
109 			if (type) {
110 				if (!strcasecmp (result->type, type) &&
111 			    	!strcasecmp (result->subtype, subtype))
112 					break;
113 			}
114 
115 		}
116 	}
117 
118 	free (type);
119 	return result;
120 }
121 
122 /* Return the index of the first decoder able to handle files with the
123  * given filename extension, or -1 if none can. */
find_extn_decoder(int * decoder_list,int count,const char * extn)124 static int find_extn_decoder (int *decoder_list, int count, const char *extn)
125 {
126 	int ix;
127 
128 	assert (decoder_list);
129 	assert (RANGE(0, count, plugins_num));
130 	assert (extn && extn[0]);
131 
132 	for (ix = 0; ix < count; ix += 1) {
133 		if (plugins[decoder_list[ix]].decoder->our_format_ext &&
134 		    plugins[decoder_list[ix]].decoder->our_format_ext (extn))
135 			return decoder_list[ix];
136 	}
137 
138 	return -1;
139 }
140 
141 /* Return the index of the first decoder able to handle audio with the
142  * given MIME media type, or -1 if none can. */
find_mime_decoder(int * decoder_list,int count,const char * mime)143 static int find_mime_decoder (int *decoder_list, int count, const char *mime)
144 {
145 	int ix;
146 
147 	assert (decoder_list);
148 	assert (RANGE(0, count, plugins_num));
149 	assert (mime && mime[0]);
150 
151 	for (ix = 0; ix < count; ix += 1) {
152 		if (plugins[decoder_list[ix]].decoder->our_format_mime &&
153 		    plugins[decoder_list[ix]].decoder->our_format_mime (mime))
154 			return decoder_list[ix];
155 	}
156 
157 	return -1;
158 }
159 
160 /* Return the index of the first decoder able to handle audio with the
161  * given filename extension and/or MIME media type, or -1 if none can. */
find_decoder(const char * extn,const char * file,char ** mime)162 static int find_decoder (const char *extn, const char *file, char **mime)
163 {
164 	int result;
165 	decoder_t_preference *pref;
166 
167 	assert ((extn && extn[0]) || (file && file[0]) || (mime && *mime));
168 
169 	pref = lookup_preference (extn, file, mime);
170 	if (pref) {
171 		if (pref->subtype)
172 			return find_mime_decoder (pref->decoder_list, pref->decoders, *mime);
173 		else
174 			return find_extn_decoder (pref->decoder_list, pref->decoders, extn);
175 	}
176 
177 	result = -1;
178 	if (mime && *mime)
179 		result = find_mime_decoder (default_decoder_list, plugins_num, *mime);
180 	if (result == -1 && extn && *extn)
181 		result = find_extn_decoder (default_decoder_list, plugins_num, extn);
182 
183 	return result;
184 }
185 
186 /* Find the index in plugins table for the given file.
187  * Return -1 if not found. */
find_type(const char * file)188 static int find_type (const char *file)
189 {
190 	int result = -1;
191 	char *extn, *mime;
192 
193 	extn = ext_pos (file);
194 	mime = NULL;
195 
196 	result = find_decoder (extn, file, &mime);
197 
198 	free (mime);
199 	return result;
200 }
201 
is_sound_file(const char * name)202 int is_sound_file (const char *name)
203 {
204 	return find_type(name) != -1 ? 1 : 0;
205 }
206 
207 /* Return short type name for the given file or NULL if not found.
208  * Not thread safe! */
file_type_name(const char * file)209 char *file_type_name (const char *file)
210 {
211 	int i;
212 	static char buf[4];
213 
214 	if (file_type (file) == F_URL) {
215 		strcpy (buf, "NET");
216 		return buf;
217 	}
218 
219 	i = find_type (file);
220 	if (i == -1)
221 		return NULL;
222 
223 	memset (buf, 0, sizeof (buf));
224 	plugins[i].decoder->get_name (file, buf);
225 
226 	assert (buf[0]);
227 
228 	return buf;
229 }
230 
get_decoder(const char * file)231 struct decoder *get_decoder (const char *file)
232 {
233 	int i;
234 
235 	i = find_type (file);
236 	if (i != -1)
237 		return plugins[i].decoder;
238 
239 	return NULL;
240 }
241 
242 /* Given a decoder pointer, return its name. */
get_decoder_name(const struct decoder * decoder)243 const char *get_decoder_name (const struct decoder *decoder)
244 {
245 	int ix;
246 	const char *result = NULL;
247 
248 	assert (decoder);
249 
250 	for (ix = 0; ix < plugins_num; ix += 1) {
251 		if (plugins[ix].decoder == decoder) {
252 			result = plugins[ix].name;
253 			break;
254 		}
255 	}
256 
257 	assert (result);
258 
259 	return result;
260 }
261 
262 /* Use the stream's MIME type to return a decoder for it, or NULL if no
263  * applicable decoder was found. */
get_decoder_by_mime_type(struct io_stream * stream)264 static struct decoder *get_decoder_by_mime_type (struct io_stream *stream)
265 {
266 	int i;
267 	char *mime;
268 	struct decoder *result;
269 
270 	result = NULL;
271 	mime = xstrdup (io_get_mime_type (stream));
272 	if (mime) {
273 		i = find_decoder (NULL, NULL, &mime);
274 		if (i != -1) {
275 			logit ("Found decoder for MIME type %s: %s", mime, plugins[i].name);
276 			result = plugins[i].decoder;
277 		}
278 		free (mime);
279 	}
280 	else
281 		logit ("No MIME type.");
282 
283 	return result;
284 }
285 
286 /* Return the decoder for this stream. */
get_decoder_by_content(struct io_stream * stream)287 struct decoder *get_decoder_by_content (struct io_stream *stream)
288 {
289 	char buf[8096];
290 	ssize_t res;
291 	int i;
292 	struct decoder *decoder_by_mime_type;
293 
294 	assert (stream != NULL);
295 
296 	/* Peek at the start of the stream to check if sufficient data is
297 	 * available.  If not, there is no sense in trying the decoders as
298 	 * each of them would issue an error.  The data is also needed to
299 	 * get the MIME type. */
300 	logit ("Testing the stream...");
301 	res = io_peek (stream, buf, sizeof (buf));
302 	if (res < 0) {
303 		error ("Stream error: %s", io_strerror (stream));
304 		return NULL;
305 	}
306 
307 	if (res < 512) {
308 		logit ("Stream too short");
309 		return NULL;
310 	}
311 
312 	decoder_by_mime_type = get_decoder_by_mime_type (stream);
313 	if (decoder_by_mime_type)
314 		return decoder_by_mime_type;
315 
316 	for (i = 0; i < plugins_num; i++) {
317 		if (plugins[i].decoder->can_decode
318 				&& plugins[i].decoder->can_decode (stream)) {
319 			logit ("Found decoder for stream: %s", plugins[i].name);
320 			return plugins[i].decoder;
321 		}
322 	}
323 
324 	error ("Format not supported");
325 	return NULL;
326 }
327 
328 /* Extract decoder name from file name. */
extract_decoder_name(const char * filename)329 static char *extract_decoder_name (const char *filename)
330 {
331 	int len;
332 	const char *ptr;
333 	char *result;
334 
335 	if (!strncmp (filename, "lib", 3))
336 		filename += 3;
337 	len = strlen (filename);
338 	ptr = strpbrk (filename, "_.-");
339 	if (ptr)
340 		len = ptr - filename;
341 	result = xmalloc (len + 1);
342 	strncpy (result, filename, len);
343 	result[len] = 0x00;
344 
345 	return result;
346 }
347 
348 /* Return the index for a decoder of the given name, or plugins_num if
349  * not found. */
lookup_decoder_by_name(const char * name)350 static int lookup_decoder_by_name (const char *name)
351 {
352 	int result;
353 
354 	assert (name && name[0]);
355 
356 	result = 0;
357 	while (result < plugins_num) {
358 		if (!strcasecmp (plugins[result].name, name))
359 			break;
360 		result += 1;
361 	}
362 
363 	return result;
364 }
365 
366 /* Return a string of concatenated driver names. */
list_decoder_names(int * decoder_list,int count)367 static char *list_decoder_names (int *decoder_list, int count)
368 {
369 	int ix;
370 	char *result;
371 	lists_t_strs *names;
372 
373 	if (count == 0)
374 		return xstrdup ("");
375 
376 	names = lists_strs_new (count);
377 	for (ix = 0; ix < count; ix += 1)
378 		lists_strs_append (names, plugins[decoder_list[ix]].name);
379 
380 	if (have_tremor) {
381 		ix = lists_strs_find (names, "vorbis");
382 		if (ix < lists_strs_size (names))
383 			lists_strs_replace (names, ix, "vorbis(tremor)");
384 	}
385 
386 	ix = lists_strs_find (names, "ffmpeg");
387 	if (ix < lists_strs_size (names)) {
388 #if defined(HAVE_FFMPEG)
389 			lists_strs_replace (names, ix, "ffmpeg");
390 #elif defined(HAVE_LIBAV)
391 			lists_strs_replace (names, ix, "ffmpeg(libav)");
392 #else
393 			lists_strs_replace (names, ix, "ffmpeg/libav");
394 #endif
395 	}
396 
397 	result = lists_strs_fmt (names, " %s");
398 	lists_strs_free (names);
399 
400 	return result;
401 }
402 
403 /* Check if this handle is already present in the plugins table.
404  * Returns 1 if so. */
present_handle(const lt_dlhandle h)405 static int present_handle (const lt_dlhandle h)
406 {
407 	int i;
408 
409 	for (i = 0; i < plugins_num; i++) {
410 		if (plugins[i].handle == h)
411 			return 1;
412 	}
413 
414 	return 0;
415 }
416 
lt_load_plugin(const char * file,lt_ptr debug_info_ptr)417 static int lt_load_plugin (const char *file, lt_ptr debug_info_ptr)
418 {
419 	int debug_info;
420 	const char *name;
421 	plugin_init_func init_func;
422 
423 	debug_info = *(int *)debug_info_ptr;
424 	name = strrchr (file, '/');
425 	name = name ? (name + 1) : file;
426 	if (debug_info)
427 		printf ("Loading plugin %s...\n", name);
428 
429 	if (plugins_num == PLUGINS_NUM) {
430 		fprintf (stderr, "Can't load plugin, because maximum number "
431 		                                    "of plugins reached!\n");
432 		return 0;
433 	}
434 
435 	plugins[plugins_num].handle = lt_dlopenext (file);
436 	if (!plugins[plugins_num].handle) {
437 		fprintf (stderr, "Can't load plugin %s: %s\n", name, lt_dlerror ());
438 		return 0;
439 	}
440 
441 	if (present_handle (plugins[plugins_num].handle)) {
442 		if (debug_info)
443 			printf ("Already loaded\n");
444 		if (lt_dlclose (plugins[plugins_num].handle))
445 			fprintf (stderr, "Error unloading plugin: %s\n", lt_dlerror ());
446 		return 0;
447 	}
448 
449 	init_func = lt_dlsym (plugins[plugins_num].handle, "plugin_init");
450 	if (!init_func) {
451 		fprintf (stderr, "No init function in the plugin!\n");
452 		if (lt_dlclose (plugins[plugins_num].handle))
453 			fprintf (stderr, "Error unloading plugin: %s\n", lt_dlerror ());
454 		return 0;
455 	}
456 
457 	plugins[plugins_num].decoder = init_func ();
458 	if (!plugins[plugins_num].decoder) {
459 		fprintf (stderr, "NULL decoder!\n");
460 		if (lt_dlclose (plugins[plugins_num].handle))
461 			fprintf (stderr, "Error unloading plugin: %s\n", lt_dlerror ());
462 		return 0;
463 	}
464 
465 	if (plugins[plugins_num].decoder->api_version != DECODER_API_VERSION) {
466 		fprintf (stderr, "Plugin uses different API version\n");
467 		if (lt_dlclose (plugins[plugins_num].handle))
468 			fprintf (stderr, "Error unloading plugin: %s\n", lt_dlerror ());
469 		return 0;
470 	}
471 
472 	plugins[plugins_num].name = extract_decoder_name (name);
473 
474 	/* Is the Vorbis decoder using Tremor? */
475 	if (!strcmp (plugins[plugins_num].name, "vorbis")) {
476 		bool (*vorbis_is_tremor)();
477 
478 		vorbis_is_tremor = lt_dlsym (plugins[plugins_num].handle,
479 		                             "vorbis_is_tremor");
480 		if (vorbis_is_tremor)
481 			have_tremor = vorbis_is_tremor ();
482 	}
483 
484 	debug ("Loaded %s decoder", plugins[plugins_num].name);
485 
486 	if (plugins[plugins_num].decoder->init)
487 		plugins[plugins_num].decoder->init ();
488 	plugins_num += 1;
489 
490 	if (debug_info)
491 		printf ("OK\n");
492 
493 	return 0;
494 }
495 
496 /* Create a new preferences entry and initialise it. */
make_preference(const char * prefix)497 static decoder_t_preference *make_preference (const char *prefix)
498 {
499 	decoder_t_preference *result;
500 
501 	assert (prefix && prefix[0]);
502 
503 	result = (decoder_t_preference *)xmalloc (
504 		offsetof (decoder_t_preference, type) + strlen (prefix) + 1
505 	);
506 	result->next = NULL;
507 	result->decoders = 0;
508 	strcpy (result->type, prefix);
509 	result->subtype = strchr (result->type, '/');
510 	if (result->subtype) {
511 		*result->subtype++ = 0x00;
512 		result->subtype = clean_mime_subtype (result->subtype);
513 	}
514 
515 	return result;
516 }
517 
518 /* Is the given decoder (by index) already in the decoder list for 'pref'? */
is_listed_decoder(decoder_t_preference * pref,int d)519 static bool is_listed_decoder (decoder_t_preference *pref, int d)
520 {
521 	int ix;
522 	bool result;
523 
524 	assert (pref);
525 	assert (d >= 0);
526 
527 	result = false;
528 	for (ix = 0; ix < pref->decoders; ix += 1) {
529 		if (d == pref->decoder_list[ix]) {
530 			result = true;
531 			break;
532 		}
533 	}
534 
535 	return result;
536 }
537 
538 /* Add the named decoder (if valid) to a preferences decoder list. */
load_each_decoder(decoder_t_preference * pref,const char * name)539 static void load_each_decoder (decoder_t_preference *pref, const char *name)
540 {
541 	int d;
542 
543 	assert (pref);
544 	assert (name && name[0]);
545 
546 	d = lookup_decoder_by_name (name);
547 
548 	/* Drop unknown decoders. */
549 	if (d == plugins_num)
550 		return;
551 
552 	/* Drop duplicate decoders. */
553 	if (is_listed_decoder (pref, d))
554 		return;
555 
556 	pref->decoder_list[pref->decoders++] = d;
557 
558 	return;
559 }
560 
561 /* Build a preference's decoder list. */
load_decoders(decoder_t_preference * pref,lists_t_strs * tokens)562 static void load_decoders (decoder_t_preference *pref, lists_t_strs *tokens)
563 {
564 	int ix, dx, asterisk_at;
565 	int decoder[PLUGINS_NUM];
566 	const char *name;
567 
568 	assert (pref);
569 	assert (tokens);
570 
571 	asterisk_at = -1;
572 
573 	/* Add the index of each known decoder to the decoders list.
574 	 * Note the position following the first asterisk. */
575 	for (ix = 1; ix < lists_strs_size (tokens); ix += 1) {
576 		name = lists_strs_at (tokens, ix);
577 		if (strcmp (name, "*"))
578 			load_each_decoder (pref, name);
579 		else if (asterisk_at == -1)
580 			asterisk_at = pref->decoders;
581 	}
582 
583 	if (asterisk_at == -1)
584 		return;
585 
586 	dx = 0;
587 
588 	/* Find decoders not already listed. */
589 	for (ix = 0; ix < plugins_num; ix += 1) {
590 		if (!is_listed_decoder (pref, ix))
591 			decoder[dx++] = ix;
592 	}
593 
594 	/* Splice asterisk decoders into the decoder list. */
595 	for (ix = 0; ix < dx; ix += 1) {
596 		pref->decoder_list[pref->decoders++] =
597 		      pref->decoder_list[asterisk_at + ix];
598 		pref->decoder_list[asterisk_at + ix] = decoder[ix];
599 	}
600 
601 	assert (RANGE(0, pref->decoders, plugins_num));
602 }
603 
604 /* Add a new preference for an audio format. */
load_each_preference(const char * preference)605 static void load_each_preference (const char *preference)
606 {
607 	const char *prefix;
608 	lists_t_strs *tokens;
609 	decoder_t_preference *pref;
610 
611 	assert (preference && preference[0]);
612 
613 	tokens = lists_strs_new (4);
614 	lists_strs_split (tokens, preference, "(,)");
615 	prefix = lists_strs_at (tokens, 0);
616 	pref = make_preference (prefix);
617 #ifdef DEBUG
618 	pref->source = preference;
619 #endif
620 	load_decoders (pref, tokens);
621 	pref->next = preferences;
622 	preferences = pref;
623 	lists_strs_free (tokens);
624 }
625 
626 /* Load all preferences given by the user in PreferredDecoders. */
load_preferences()627 static void load_preferences ()
628 {
629 	int ix;
630 	const char *preference;
631 	lists_t_strs *list;
632 
633 	list = options_get_list ("PreferredDecoders");
634 
635 	for (ix = 0; ix < lists_strs_size (list); ix += 1) {
636 		preference = lists_strs_at (list, ix);
637 		load_each_preference (preference);
638 	}
639 
640 #ifdef DEBUG
641 	{
642 		char *names;
643 		decoder_t_preference *pref;
644 
645 		for (pref = preferences; pref; pref = pref->next) {
646 			names = list_decoder_names (pref->decoder_list, pref->decoders);
647 			debug ("%s:%s", pref->source, names);
648 			free (names);
649 		}
650 	}
651 #endif
652 }
653 
load_plugins(int debug_info)654 static void load_plugins (int debug_info)
655 {
656 	int ix;
657 	char *names;
658 
659 	if (debug_info)
660 		printf ("Loading plugins from %s...\n", PLUGIN_DIR);
661 	if (lt_dlinit ())
662 		fatal ("lt_dlinit() failed: %s", lt_dlerror ());
663 
664 	if (lt_dlforeachfile (PLUGIN_DIR, &lt_load_plugin, &debug_info))
665 		fatal ("Can't load plugins: %s", lt_dlerror ());
666 
667 	if (plugins_num == 0)
668 		fatal ("No decoder plugins have been loaded!");
669 
670 	for (ix = 0; ix < plugins_num; ix += 1)
671 		default_decoder_list[ix] = ix;
672 
673 	names = list_decoder_names (default_decoder_list, plugins_num);
674 	logit ("Loaded %d decoders:%s", plugins_num, names);
675 	free (names);
676 }
677 
decoder_init(int debug_info)678 void decoder_init (int debug_info)
679 {
680 	load_plugins (debug_info);
681 	load_preferences ();
682 }
683 
cleanup_decoders()684 static void cleanup_decoders ()
685 {
686 	int ix;
687 
688 	for (ix = 0; ix < plugins_num; ix++) {
689 		if (plugins[ix].decoder->destroy)
690 			plugins[ix].decoder->destroy ();
691 		free (plugins[ix].name);
692 		if (plugins[ix].handle)
693 			lt_dlclose (plugins[ix].handle);
694 	}
695 
696 	if (lt_dlexit ())
697 		logit ("lt_exit() failed: %s", lt_dlerror ());
698 }
699 
cleanup_preferences()700 static void cleanup_preferences ()
701 {
702 	decoder_t_preference *pref, *next;
703 
704 	pref = preferences;
705 	for (pref = preferences; pref; pref = next) {
706 		next = pref->next;
707 		free (pref);
708 	}
709 
710 	preferences = NULL;
711 }
712 
decoder_cleanup()713 void decoder_cleanup ()
714 {
715 	cleanup_decoders ();
716 	cleanup_preferences ();
717 }
718 
719 /* Fill the error structure with an error of a given type and message.
720  * strerror(add_errno) is appended at the end of the message if add_errno != 0.
721  * The old error message is free()ed.
722  * This is thread safe; use this instead of constructs using strerror(). */
decoder_error(struct decoder_error * error,const enum decoder_error_type type,const int add_errno,const char * format,...)723 void decoder_error (struct decoder_error *error,
724 		const enum decoder_error_type type, const int add_errno,
725 		const char *format, ...)
726 {
727 	char errno_buf[256] = "";
728 	char *err_str;
729 	va_list va;
730 
731 	if (error->err)
732 		free (error->err);
733 
734 	error->type = type;
735 
736 	va_start (va, format);
737 	err_str = format_msg_va (format, va);
738 	va_end (va);
739 
740 	if (add_errno)
741 		strerror_r(add_errno, errno_buf, sizeof(errno_buf));
742 
743 	error->err = format_msg ("%s%s", err_str, errno_buf);
744 
745 	free (err_str);
746 }
747 
748 /* Initialize the decoder_error structure. */
decoder_error_init(struct decoder_error * error)749 void decoder_error_init (struct decoder_error *error)
750 {
751 	error->type = ERROR_OK;
752 	error->err = NULL;
753 }
754 
755 /* Set the decoder_error structure to contain "success" information. */
decoder_error_clear(struct decoder_error * error)756 void decoder_error_clear (struct decoder_error *error)
757 {
758 	error->type = ERROR_OK;
759 	if (error->err) {
760 		free (error->err);
761 		error->err = NULL;
762 	}
763 }
764 
decoder_error_copy(struct decoder_error * dst,const struct decoder_error * src)765 void decoder_error_copy (struct decoder_error *dst,
766 		const struct decoder_error *src)
767 {
768 	dst->type = src->type;
769 	dst->err = xstrdup (src->err);
770 }
771 
772 /* Return the error text from the decoder_error variable. */
decoder_error_text(const struct decoder_error * error)773 const char *decoder_error_text (const struct decoder_error *error)
774 {
775 	return error->err;
776 }
777