seektable.c 3.73 KB
Newer Older
Josh Coalson's avatar
Josh Coalson committed
1
/* grabbag - Convenience lib for various routines common to several tools
2
3
 * Copyright (C) 2002-2009  Josh Coalson
 * Copyright (C) 2011-2013  Xiph.Org Foundation
Josh Coalson's avatar
Josh Coalson committed
4
 *
5
6
7
8
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
Josh Coalson's avatar
Josh Coalson committed
9
 *
10
 * This library is distributed in the hope that it will be useful,
Josh Coalson's avatar
Josh Coalson committed
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
Josh Coalson's avatar
Josh Coalson committed
14
 *
15
16
17
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
Josh Coalson's avatar
Josh Coalson committed
18
19
 */

20
#ifdef HAVE_CONFIG_H
Josh Coalson's avatar
Josh Coalson committed
21
22
23
#  include <config.h>
#endif

Josh Coalson's avatar
Josh Coalson committed
24
#include "share/grabbag.h"
25
#include "share/compat.h"
Josh Coalson's avatar
Josh Coalson committed
26
27
28
29
#include "FLAC/assert.h"
#include <stdlib.h> /* for atoi() */
#include <string.h>

30
FLAC__bool grabbag__seektable_convert_specification_to_template(const char *spec, FLAC__bool only_explicit_placeholders, FLAC__uint64 total_samples_to_encode, unsigned sample_rate, FLAC__StreamMetadata *seektable_template, FLAC__bool *spec_has_real_points)
Josh Coalson's avatar
Josh Coalson committed
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
{
	unsigned i;
	const char *pt;

	FLAC__ASSERT(0 != spec);
	FLAC__ASSERT(0 != seektable_template);
	FLAC__ASSERT(seektable_template->type = FLAC__METADATA_TYPE_SEEKTABLE);

	if(0 != spec_has_real_points)
		*spec_has_real_points = false;

	for(pt = spec, i = 0; pt && *pt; i++) {
		const char *q = strchr(pt, ';');
		FLAC__ASSERT(0 != q);

		if(q > pt) {
			if(0 == strncmp(pt, "X;", 2)) { /* -S X */
				if(!FLAC__metadata_object_seektable_template_append_placeholders(seektable_template, 1))
					return false;
			}
			else if(q[-1] == 'x') { /* -S #x */
				if(total_samples_to_encode > 0) { /* we can only do these if we know the number of samples to encode up front */
					if(0 != spec_has_real_points)
						*spec_has_real_points = true;
					if(!only_explicit_placeholders) {
56
57
58
59
						const int n = (unsigned)atoi(pt);
						if(n > 0)
							if(!FLAC__metadata_object_seektable_template_append_spaced_points(seektable_template, (unsigned)n, total_samples_to_encode))
								return false;
Josh Coalson's avatar
Josh Coalson committed
60
61
62
63
64
65
66
67
68
					}
				}
			}
			else if(q[-1] == 's') { /* -S #s */
				if(total_samples_to_encode > 0) { /* we can only do these if we know the number of samples to encode up front */
					FLAC__ASSERT(sample_rate > 0);
					if(0 != spec_has_real_points)
						*spec_has_real_points = true;
					if(!only_explicit_placeholders) {
69
						const double sec = atof(pt);
Josh Coalson's avatar
Josh Coalson committed
70
						if(sec > 0.0) {
71
72
73
74
75
76
							unsigned samples = (unsigned)(sec * (double)sample_rate);
							if(samples > 0) {
								/* +1 for the initial point at sample 0 */
								if(!FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(seektable_template, samples, total_samples_to_encode))
									return false;
							}
Josh Coalson's avatar
Josh Coalson committed
77
78
79
80
81
82
83
84
						}
					}
				}
			}
			else { /* -S # */
				if(0 != spec_has_real_points)
					*spec_has_real_points = true;
				if(!only_explicit_placeholders) {
85
86
					char *endptr;
					const FLAC__int64 n = (FLAC__int64)strtoll(pt, &endptr, 10);
87
88
89
90
					if(
						(n > 0 || (endptr > pt && *endptr == ';')) && /* is a valid number (extra check needed for "0") */
						(total_samples_to_encode == 0 || (FLAC__uint64)n < total_samples_to_encode) /* number is not >= the known total_samples_to_encode */
					)
91
92
						if(!FLAC__metadata_object_seektable_template_append_point(seektable_template, (FLAC__uint64)n))
							return false;
Josh Coalson's avatar
Josh Coalson committed
93
94
95
96
97
98
99
100
101
102
103
104
				}
			}
		}

		pt = ++q;
	}

	if(!FLAC__metadata_object_seektable_template_sort(seektable_template, /*compact=*/true))
		return false;

	return true;
}