blob: 6e8426e91c7bc5aa9c72489cb06a5376ba69a257 [file] [log] [blame]
Josh Coalson26560dd2001-02-08 00:38:41 +00001/* libFLAC - Free Lossless Audio Codec library
Erik de Castro Lopob1982fb2013-05-25 17:11:19 +10002 * Copyright (C) 2000-2009 Josh Coalson
Erik de Castro Lopo6a5fe432016-12-05 06:35:39 +11003 * Copyright (C) 2011-2016 Xiph.Org Foundation
Josh Coalsonbb7f6b92000-12-10 04:09:52 +00004 *
Josh Coalsonafd81072003-01-31 23:34:56 +00005 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
Josh Coalsonbb7f6b92000-12-10 04:09:52 +00008 *
Josh Coalsonafd81072003-01-31 23:34:56 +00009 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000011 *
Josh Coalsonafd81072003-01-31 23:34:56 +000012 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * - Neither the name of the Xiph.org Foundation nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000031 */
32
Erik de Castro Lopo006b8352014-03-23 21:59:46 +110033#ifdef HAVE_CONFIG_H
Josh Coalsonb1ec7962006-05-24 04:41:36 +000034# include <config.h>
35#endif
36
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000037#include <stdio.h>
Josh Coalson5a5de732002-08-01 06:37:11 +000038#include <stdlib.h> /* for qsort() */
Josh Coalsonb47ab0d2007-06-16 00:50:28 +000039#include <string.h> /* for memset() */
Josh Coalson0d36cbd2002-07-15 05:24:56 +000040#include "FLAC/assert.h"
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000041#include "FLAC/format.h"
Erik de Castro Lopod9ae5e92015-08-22 19:22:50 +100042#include "share/alloc.h"
Erik de Castro Lopo5b62b772012-06-22 14:52:53 +100043#include "share/compat.h"
Josh Coalsoncda4c3c2002-08-17 15:21:29 +000044#include "private/format.h"
Cristian Rodríguezf0296252012-04-05 19:39:37 -030045#include "private/macros.h"
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000046
Josh Coalson82738b32002-09-25 06:09:47 +000047/* VERSION should come from configure */
Josh Coalson6afed9f2002-10-16 22:29:47 +000048FLAC_API const char *FLAC__VERSION_STRING = VERSION;
Josh Coalson82738b32002-09-25 06:09:47 +000049
Erik de Castro Lopoccdd8fe2014-11-26 06:41:51 +110050FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC " VERSION " 20141125";
Josh Coalson0aad38b2002-09-09 05:06:51 +000051
Josh Coalson6afed9f2002-10-16 22:29:47 +000052FLAC_API const FLAC__byte FLAC__STREAM_SYNC_STRING[4] = { 'f','L','a','C' };
53FLAC_API const unsigned FLAC__STREAM_SYNC = 0x664C6143;
Josh Coalson38892872005-08-31 00:18:18 +000054FLAC_API const unsigned FLAC__STREAM_SYNC_LEN = 32; /* bits */
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000055
Josh Coalson6afed9f2002-10-16 22:29:47 +000056FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN = 16; /* bits */
57FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN = 16; /* bits */
58FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN = 24; /* bits */
59FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN = 24; /* bits */
60FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN = 20; /* bits */
61FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN = 3; /* bits */
62FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN = 5; /* bits */
63FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN = 36; /* bits */
64FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN = 128; /* bits */
Josh Coalson20135722001-02-23 21:05:53 +000065
Josh Coalson6afed9f2002-10-16 22:29:47 +000066FLAC_API const unsigned FLAC__STREAM_METADATA_APPLICATION_ID_LEN = 32; /* bits */
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000067
Josh Coalson6afed9f2002-10-16 22:29:47 +000068FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN = 64; /* bits */
69FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN = 64; /* bits */
70FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN = 16; /* bits */
Josh Coalsonc5d08e02001-04-10 19:13:50 +000071
Josh Coalson49623ea2004-07-29 06:28:59 +000072FLAC_API const FLAC__uint64 FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER = FLAC__U64L(0xffffffffffffffff);
Josh Coalson167658a2001-04-13 18:22:25 +000073
Josh Coalson6afed9f2002-10-16 22:29:47 +000074FLAC_API const unsigned FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN = 32; /* bits */
75FLAC_API const unsigned FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN = 32; /* bits */
Josh Coalsoncc059bc2002-05-04 17:35:51 +000076
Josh Coalson8e9c4512002-11-14 05:00:24 +000077FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN = 64; /* bits */
78FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN = 8; /* bits */
Josh Coalsonb3538c82003-01-12 08:42:23 +000079FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN = 3*8; /* bits */
Josh Coalson8e9c4512002-11-14 05:00:24 +000080
81FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN = 64; /* bits */
82FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN = 8; /* bits */
83FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN = 12*8; /* bits */
84FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN = 1; /* bit */
85FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN = 1; /* bit */
Josh Coalsonb3538c82003-01-12 08:42:23 +000086FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN = 6+13*8; /* bits */
Josh Coalson8e9c4512002-11-14 05:00:24 +000087FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN = 8; /* bits */
88
89FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN = 128*8; /* bits */
90FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN = 64; /* bits */
Josh Coalson8f0c71b2002-12-05 06:37:46 +000091FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN = 1; /* bit */
Josh Coalsonb3538c82003-01-12 08:42:23 +000092FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN = 7+258*8; /* bits */
Josh Coalson8e9c4512002-11-14 05:00:24 +000093FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN = 8; /* bits */
94
Josh Coalsone343ab22006-09-23 19:21:19 +000095FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_TYPE_LEN = 32; /* bits */
96FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN = 32; /* bits */
97FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN = 32; /* bits */
98FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN = 32; /* bits */
99FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN = 32; /* bits */
100FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN = 32; /* bits */
Josh Coalson74ed2942006-09-23 23:15:05 +0000101FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_COLORS_LEN = 32; /* bits */
Josh Coalsone343ab22006-09-23 19:21:19 +0000102FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN = 32; /* bits */
103
Josh Coalson6afed9f2002-10-16 22:29:47 +0000104FLAC_API const unsigned FLAC__STREAM_METADATA_IS_LAST_LEN = 1; /* bits */
105FLAC_API const unsigned FLAC__STREAM_METADATA_TYPE_LEN = 7; /* bits */
106FLAC_API const unsigned FLAC__STREAM_METADATA_LENGTH_LEN = 24; /* bits */
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000107
Josh Coalson6afed9f2002-10-16 22:29:47 +0000108FLAC_API const unsigned FLAC__FRAME_HEADER_SYNC = 0x3ffe;
109FLAC_API const unsigned FLAC__FRAME_HEADER_SYNC_LEN = 14; /* bits */
Josh Coalsonb47ab0d2007-06-16 00:50:28 +0000110FLAC_API const unsigned FLAC__FRAME_HEADER_RESERVED_LEN = 1; /* bits */
111FLAC_API const unsigned FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN = 1; /* bits */
Josh Coalson6afed9f2002-10-16 22:29:47 +0000112FLAC_API const unsigned FLAC__FRAME_HEADER_BLOCK_SIZE_LEN = 4; /* bits */
113FLAC_API const unsigned FLAC__FRAME_HEADER_SAMPLE_RATE_LEN = 4; /* bits */
114FLAC_API const unsigned FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN = 4; /* bits */
115FLAC_API const unsigned FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN = 3; /* bits */
116FLAC_API const unsigned FLAC__FRAME_HEADER_ZERO_PAD_LEN = 1; /* bits */
117FLAC_API const unsigned FLAC__FRAME_HEADER_CRC_LEN = 8; /* bits */
Josh Coalson215af572001-03-27 01:15:58 +0000118
Josh Coalson6afed9f2002-10-16 22:29:47 +0000119FLAC_API const unsigned FLAC__FRAME_FOOTER_CRC_LEN = 16; /* bits */
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000120
Josh Coalson6afed9f2002-10-16 22:29:47 +0000121FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_TYPE_LEN = 2; /* bits */
122FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN = 4; /* bits */
123FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN = 4; /* bits */
Josh Coalsonb47ab0d2007-06-16 00:50:28 +0000124FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN = 5; /* bits */
Josh Coalson6afed9f2002-10-16 22:29:47 +0000125FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN = 5; /* bits */
Josh Coalson2051dd42001-04-12 22:22:34 +0000126
Josh Coalson6afed9f2002-10-16 22:29:47 +0000127FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER = 15; /* == (1<<FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN)-1 */
Josh Coalsonb47ab0d2007-06-16 00:50:28 +0000128FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER = 31; /* == (1<<FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN)-1 */
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000129
Josh Coalson6afed9f2002-10-16 22:29:47 +0000130FLAC_API const char * const FLAC__EntropyCodingMethodTypeString[] = {
Josh Coalsonb47ab0d2007-06-16 00:50:28 +0000131 "PARTITIONED_RICE",
132 "PARTITIONED_RICE2"
Josh Coalson75d0a0b2001-01-24 00:42:16 +0000133};
134
Josh Coalson6afed9f2002-10-16 22:29:47 +0000135FLAC_API const unsigned FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN = 4; /* bits */
136FLAC_API const unsigned FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN = 5; /* bits */
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000137
Josh Coalson6afed9f2002-10-16 22:29:47 +0000138FLAC_API const unsigned FLAC__SUBFRAME_ZERO_PAD_LEN = 1; /* bits */
139FLAC_API const unsigned FLAC__SUBFRAME_TYPE_LEN = 6; /* bits */
140FLAC_API const unsigned FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN = 1; /* bits */
Josh Coalson215af572001-03-27 01:15:58 +0000141
Josh Coalson6afed9f2002-10-16 22:29:47 +0000142FLAC_API const unsigned FLAC__SUBFRAME_TYPE_CONSTANT_BYTE_ALIGNED_MASK = 0x00;
143FLAC_API const unsigned FLAC__SUBFRAME_TYPE_VERBATIM_BYTE_ALIGNED_MASK = 0x02;
144FLAC_API const unsigned FLAC__SUBFRAME_TYPE_FIXED_BYTE_ALIGNED_MASK = 0x10;
145FLAC_API const unsigned FLAC__SUBFRAME_TYPE_LPC_BYTE_ALIGNED_MASK = 0x40;
Josh Coalson75d0a0b2001-01-24 00:42:16 +0000146
Josh Coalson6afed9f2002-10-16 22:29:47 +0000147FLAC_API const char * const FLAC__SubframeTypeString[] = {
Josh Coalson75d0a0b2001-01-24 00:42:16 +0000148 "CONSTANT",
149 "VERBATIM",
150 "FIXED",
151 "LPC"
152};
153
Josh Coalson6afed9f2002-10-16 22:29:47 +0000154FLAC_API const char * const FLAC__ChannelAssignmentString[] = {
Josh Coalson75d0a0b2001-01-24 00:42:16 +0000155 "INDEPENDENT",
156 "LEFT_SIDE",
157 "RIGHT_SIDE",
158 "MID_SIDE"
159};
160
Josh Coalson6afed9f2002-10-16 22:29:47 +0000161FLAC_API const char * const FLAC__FrameNumberTypeString[] = {
Josh Coalson96084632001-07-16 18:07:12 +0000162 "FRAME_NUMBER_TYPE_FRAME_NUMBER",
163 "FRAME_NUMBER_TYPE_SAMPLE_NUMBER"
164};
165
Josh Coalson6afed9f2002-10-16 22:29:47 +0000166FLAC_API const char * const FLAC__MetadataTypeString[] = {
Josh Coalson20135722001-02-23 21:05:53 +0000167 "STREAMINFO",
168 "PADDING",
Josh Coalson9b04be72001-06-14 18:57:53 +0000169 "APPLICATION",
Josh Coalson7e19b542002-04-25 05:53:09 +0000170 "SEEKTABLE",
Josh Coalsone4869382002-11-15 05:41:48 +0000171 "VORBIS_COMMENT",
Josh Coalsone343ab22006-09-23 19:21:19 +0000172 "CUESHEET",
173 "PICTURE"
174};
175
176FLAC_API const char * const FLAC__StreamMetadata_Picture_TypeString[] = {
177 "Other",
178 "32x32 pixels 'file icon' (PNG only)",
179 "Other file icon",
180 "Cover (front)",
181 "Cover (back)",
182 "Leaflet page",
183 "Media (e.g. label side of CD)",
184 "Lead artist/lead performer/soloist",
185 "Artist/performer",
186 "Conductor",
187 "Band/Orchestra",
188 "Composer",
189 "Lyricist/text writer",
190 "Recording Location",
191 "During recording",
192 "During performance",
193 "Movie/video screen capture",
194 "A bright coloured fish",
195 "Illustration",
196 "Band/artist logotype",
197 "Publisher/Studio logotype"
Josh Coalson75d0a0b2001-01-24 00:42:16 +0000198};
Josh Coalsoncc059bc2002-05-04 17:35:51 +0000199
Josh Coalson6afed9f2002-10-16 22:29:47 +0000200FLAC_API FLAC__bool FLAC__format_sample_rate_is_valid(unsigned sample_rate)
Josh Coalsoncc059bc2002-05-04 17:35:51 +0000201{
Josh Coalson2258fa82007-03-30 01:02:40 +0000202 if(sample_rate == 0 || sample_rate > FLAC__MAX_SAMPLE_RATE) {
203 return false;
204 }
205 else
206 return true;
207}
208
Josh Coalson1be89c42008-05-27 05:19:52 +0000209FLAC_API FLAC__bool FLAC__format_blocksize_is_subset(unsigned blocksize, unsigned sample_rate)
210{
211 if(blocksize > 16384)
212 return false;
213 else if(sample_rate <= 48000 && blocksize > 4608)
214 return false;
215 else
216 return true;
217}
218
Josh Coalson2258fa82007-03-30 01:02:40 +0000219FLAC_API FLAC__bool FLAC__format_sample_rate_is_subset(unsigned sample_rate)
220{
Josh Coalsoncc059bc2002-05-04 17:35:51 +0000221 if(
Josh Coalson2258fa82007-03-30 01:02:40 +0000222 !FLAC__format_sample_rate_is_valid(sample_rate) ||
Josh Coalsoncc059bc2002-05-04 17:35:51 +0000223 (
Josh Coalson765ff502002-08-27 05:46:11 +0000224 sample_rate >= (1u << 16) &&
Josh Coalsoncc059bc2002-05-04 17:35:51 +0000225 !(sample_rate % 1000 == 0 || sample_rate % 10 == 0)
226 )
227 ) {
228 return false;
229 }
230 else
231 return true;
232}
Josh Coalson0d36cbd2002-07-15 05:24:56 +0000233
Josh Coalson504dcaf2007-09-13 15:42:47 +0000234/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */
Josh Coalson6afed9f2002-10-16 22:29:47 +0000235FLAC_API FLAC__bool FLAC__format_seektable_is_legal(const FLAC__StreamMetadata_SeekTable *seek_table)
Josh Coalson0d36cbd2002-07-15 05:24:56 +0000236{
237 unsigned i;
238 FLAC__uint64 prev_sample_number = 0;
239 FLAC__bool got_prev = false;
240
241 FLAC__ASSERT(0 != seek_table);
242
243 for(i = 0; i < seek_table->num_points; i++) {
244 if(got_prev) {
Josh Coalson5a5de732002-08-01 06:37:11 +0000245 if(
246 seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER &&
247 seek_table->points[i].sample_number <= prev_sample_number
248 )
Josh Coalson0d36cbd2002-07-15 05:24:56 +0000249 return false;
250 }
251 prev_sample_number = seek_table->points[i].sample_number;
252 got_prev = true;
253 }
254
255 return true;
256}
Josh Coalson5a5de732002-08-01 06:37:11 +0000257
258/* used as the sort predicate for qsort() */
259static int seekpoint_compare_(const FLAC__StreamMetadata_SeekPoint *l, const FLAC__StreamMetadata_SeekPoint *r)
260{
261 /* we don't just 'return l->sample_number - r->sample_number' since the result (FLAC__int64) might overflow an 'int' */
262 if(l->sample_number == r->sample_number)
263 return 0;
264 else if(l->sample_number < r->sample_number)
265 return -1;
266 else
267 return 1;
268}
269
Josh Coalson504dcaf2007-09-13 15:42:47 +0000270/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */
Josh Coalson6afed9f2002-10-16 22:29:47 +0000271FLAC_API unsigned FLAC__format_seektable_sort(FLAC__StreamMetadata_SeekTable *seek_table)
Josh Coalson5a5de732002-08-01 06:37:11 +0000272{
273 unsigned i, j;
274 FLAC__bool first;
275
Josh Coalsona0ac09a2002-08-16 05:40:16 +0000276 FLAC__ASSERT(0 != seek_table);
277
Erik de Castro Lopoa1458162015-08-26 17:13:39 +1000278 if (seek_table->num_points == 0)
279 return 0;
280
Josh Coalson5a5de732002-08-01 06:37:11 +0000281 /* sort the seekpoints */
282 qsort(seek_table->points, seek_table->num_points, sizeof(FLAC__StreamMetadata_SeekPoint), (int (*)(const void *, const void *))seekpoint_compare_);
283
284 /* uniquify the seekpoints */
285 first = true;
286 for(i = j = 0; i < seek_table->num_points; i++) {
287 if(seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER) {
288 if(!first) {
289 if(seek_table->points[i].sample_number == seek_table->points[j-1].sample_number)
290 continue;
291 }
292 }
293 first = false;
294 seek_table->points[j++] = seek_table->points[i];
295 }
296
Josh Coalson08a62822002-08-01 07:33:36 +0000297 for(i = j; i < seek_table->num_points; i++) {
298 seek_table->points[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
299 seek_table->points[i].stream_offset = 0;
300 seek_table->points[i].frame_samples = 0;
Josh Coalson5a5de732002-08-01 06:37:11 +0000301 }
302
303 return j;
304}
Josh Coalsoncda4c3c2002-08-17 15:21:29 +0000305
Josh Coalsonf2a8e062005-08-24 07:37:11 +0000306/*
307 * also disallows non-shortest-form encodings, c.f.
308 * http://www.unicode.org/versions/corrigendum1.html
309 * and a more clear explanation at the end of this section:
310 * http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
311 */
Josh Coalson8e28e432009-01-03 02:10:18 +0000312static unsigned utf8len_(const FLAC__byte *utf8)
Josh Coalson2de11242004-12-30 03:41:19 +0000313{
314 FLAC__ASSERT(0 != utf8);
Josh Coalsonf2a8e062005-08-24 07:37:11 +0000315 if ((utf8[0] & 0x80) == 0) {
Josh Coalson2de11242004-12-30 03:41:19 +0000316 return 1;
Josh Coalsonf2a8e062005-08-24 07:37:11 +0000317 }
318 else if ((utf8[0] & 0xE0) == 0xC0 && (utf8[1] & 0xC0) == 0x80) {
Josh Coalsonc6e53da2005-08-25 00:22:06 +0000319 if ((utf8[0] & 0xFE) == 0xC0) /* overlong sequence check */
Josh Coalsonf2a8e062005-08-24 07:37:11 +0000320 return 0;
Josh Coalson2de11242004-12-30 03:41:19 +0000321 return 2;
Josh Coalsonf2a8e062005-08-24 07:37:11 +0000322 }
323 else if ((utf8[0] & 0xF0) == 0xE0 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80) {
324 if (utf8[0] == 0xE0 && (utf8[1] & 0xE0) == 0x80) /* overlong sequence check */
325 return 0;
326 /* illegal surrogates check (U+D800...U+DFFF and U+FFFE...U+FFFF) */
327 if (utf8[0] == 0xED && (utf8[1] & 0xE0) == 0xA0) /* D800-DFFF */
328 return 0;
329 if (utf8[0] == 0xEF && utf8[1] == 0xBF && (utf8[2] & 0xFE) == 0xBE) /* FFFE-FFFF */
330 return 0;
Josh Coalson2de11242004-12-30 03:41:19 +0000331 return 3;
Josh Coalsonf2a8e062005-08-24 07:37:11 +0000332 }
333 else if ((utf8[0] & 0xF8) == 0xF0 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80) {
334 if (utf8[0] == 0xF0 && (utf8[1] & 0xF0) == 0x80) /* overlong sequence check */
335 return 0;
336 return 4;
337 }
338 else if ((utf8[0] & 0xFC) == 0xF8 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80 && (utf8[4] & 0xC0) == 0x80) {
339 if (utf8[0] == 0xF8 && (utf8[1] & 0xF8) == 0x80) /* overlong sequence check */
340 return 0;
341 return 5;
342 }
343 else if ((utf8[0] & 0xFE) == 0xFC && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80 && (utf8[4] & 0xC0) == 0x80 && (utf8[5] & 0xC0) == 0x80) {
344 if (utf8[0] == 0xFC && (utf8[1] & 0xFC) == 0x80) /* overlong sequence check */
345 return 0;
346 return 6;
347 }
348 else {
Josh Coalson2de11242004-12-30 03:41:19 +0000349 return 0;
Josh Coalsonf2a8e062005-08-24 07:37:11 +0000350 }
Josh Coalson2de11242004-12-30 03:41:19 +0000351}
352
353FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_name_is_legal(const char *name)
354{
355 char c;
356 for(c = *name; c; c = *(++name))
357 if(c < 0x20 || c == 0x3d || c > 0x7d)
358 return false;
359 return true;
360}
361
362FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_value_is_legal(const FLAC__byte *value, unsigned length)
363{
364 if(length == (unsigned)(-1)) {
365 while(*value) {
366 unsigned n = utf8len_(value);
367 if(n == 0)
368 return false;
369 value += n;
370 }
371 }
372 else {
373 const FLAC__byte *end = value + length;
374 while(value < end) {
375 unsigned n = utf8len_(value);
376 if(n == 0)
377 return false;
378 value += n;
379 }
380 if(value != end)
381 return false;
382 }
383 return true;
384}
385
386FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_is_legal(const FLAC__byte *entry, unsigned length)
387{
388 const FLAC__byte *s, *end;
389
390 for(s = entry, end = s + length; s < end && *s != '='; s++) {
391 if(*s < 0x20 || *s > 0x7D)
392 return false;
393 }
394 if(s == end)
395 return false;
396
397 s++; /* skip '=' */
398
399 while(s < end) {
400 unsigned n = utf8len_(s);
401 if(n == 0)
402 return false;
403 s += n;
404 }
405 if(s != end)
406 return false;
407
408 return true;
409}
410
Josh Coalson504dcaf2007-09-13 15:42:47 +0000411/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */
Josh Coalson8e9c4512002-11-14 05:00:24 +0000412FLAC_API FLAC__bool FLAC__format_cuesheet_is_legal(const FLAC__StreamMetadata_CueSheet *cue_sheet, FLAC__bool check_cd_da_subset, const char **violation)
413{
414 unsigned i, j;
415
416 if(check_cd_da_subset) {
417 if(cue_sheet->lead_in < 2 * 44100) {
418 if(violation) *violation = "CD-DA cue sheet must have a lead-in length of at least 2 seconds";
419 return false;
420 }
421 if(cue_sheet->lead_in % 588 != 0) {
422 if(violation) *violation = "CD-DA cue sheet lead-in length must be evenly divisible by 588 samples";
423 return false;
424 }
425 }
426
427 if(cue_sheet->num_tracks == 0) {
428 if(violation) *violation = "cue sheet must have at least one track (the lead-out)";
429 return false;
430 }
431
432 if(check_cd_da_subset && cue_sheet->tracks[cue_sheet->num_tracks-1].number != 170) {
433 if(violation) *violation = "CD-DA cue sheet must have a lead-out track number 170 (0xAA)";
434 return false;
435 }
436
437 for(i = 0; i < cue_sheet->num_tracks; i++) {
438 if(cue_sheet->tracks[i].number == 0) {
439 if(violation) *violation = "cue sheet may not have a track number 0";
440 return false;
441 }
442
443 if(check_cd_da_subset) {
444 if(!((cue_sheet->tracks[i].number >= 1 && cue_sheet->tracks[i].number <= 99) || cue_sheet->tracks[i].number == 170)) {
445 if(violation) *violation = "CD-DA cue sheet track number must be 1-99 or 170";
446 return false;
447 }
448 }
449
450 if(check_cd_da_subset && cue_sheet->tracks[i].offset % 588 != 0) {
Josh Coalsonf2a8e062005-08-24 07:37:11 +0000451 if(violation) {
Josh Coalsonfe1d3112005-08-24 00:14:23 +0000452 if(i == cue_sheet->num_tracks-1) /* the lead-out track... */
453 *violation = "CD-DA cue sheet lead-out offset must be evenly divisible by 588 samples";
454 else
455 *violation = "CD-DA cue sheet track offset must be evenly divisible by 588 samples";
Josh Coalsonf2a8e062005-08-24 07:37:11 +0000456 }
Josh Coalson8e9c4512002-11-14 05:00:24 +0000457 return false;
458 }
459
Josh Coalson3f86cc72002-11-21 06:41:46 +0000460 if(i < cue_sheet->num_tracks - 1) {
461 if(cue_sheet->tracks[i].num_indices == 0) {
462 if(violation) *violation = "cue sheet track must have at least one index point";
463 return false;
464 }
Josh Coalson8e9c4512002-11-14 05:00:24 +0000465
Josh Coalson3f86cc72002-11-21 06:41:46 +0000466 if(cue_sheet->tracks[i].indices[0].number > 1) {
467 if(violation) *violation = "cue sheet track's first index number must be 0 or 1";
468 return false;
469 }
Josh Coalson8e9c4512002-11-14 05:00:24 +0000470 }
471
472 for(j = 0; j < cue_sheet->tracks[i].num_indices; j++) {
473 if(check_cd_da_subset && cue_sheet->tracks[i].indices[j].offset % 588 != 0) {
474 if(violation) *violation = "CD-DA cue sheet track index offset must be evenly divisible by 588 samples";
475 return false;
476 }
477
478 if(j > 0) {
479 if(cue_sheet->tracks[i].indices[j].number != cue_sheet->tracks[i].indices[j-1].number + 1) {
480 if(violation) *violation = "cue sheet track index numbers must increase by 1";
481 return false;
482 }
483 }
484 }
485 }
486
487 return true;
488}
489
Josh Coalson504dcaf2007-09-13 15:42:47 +0000490/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */
Josh Coalsone343ab22006-09-23 19:21:19 +0000491FLAC_API FLAC__bool FLAC__format_picture_is_legal(const FLAC__StreamMetadata_Picture *picture, const char **violation)
492{
493 char *p;
494 FLAC__byte *b;
495
496 for(p = picture->mime_type; *p; p++) {
497 if(*p < 0x20 || *p > 0x7e) {
498 if(violation) *violation = "MIME type string must contain only printable ASCII characters (0x20-0x7e)";
499 return false;
500 }
501 }
502
503 for(b = picture->description; *b; ) {
504 unsigned n = utf8len_(b);
505 if(n == 0) {
506 if(violation) *violation = "description string must be valid UTF-8";
507 return false;
508 }
509 b += n;
510 }
511
512 return true;
513}
514
Josh Coalson8e9c4512002-11-14 05:00:24 +0000515/*
516 * These routines are private to libFLAC
517 */
Josh Coalsoncda4c3c2002-08-17 15:21:29 +0000518unsigned FLAC__format_get_max_rice_partition_order(unsigned blocksize, unsigned predictor_order)
519{
520 return
521 FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(
522 FLAC__format_get_max_rice_partition_order_from_blocksize(blocksize),
523 blocksize,
524 predictor_order
525 );
526}
527
528unsigned FLAC__format_get_max_rice_partition_order_from_blocksize(unsigned blocksize)
529{
530 unsigned max_rice_partition_order = 0;
531 while(!(blocksize & 1)) {
532 max_rice_partition_order++;
533 blocksize >>= 1;
534 }
Cristian Rodríguezf0296252012-04-05 19:39:37 -0300535 return flac_min(FLAC__MAX_RICE_PARTITION_ORDER, max_rice_partition_order);
Josh Coalsoncda4c3c2002-08-17 15:21:29 +0000536}
537
538unsigned FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(unsigned limit, unsigned blocksize, unsigned predictor_order)
539{
540 unsigned max_rice_partition_order = limit;
541
542 while(max_rice_partition_order > 0 && (blocksize >> max_rice_partition_order) <= predictor_order)
543 max_rice_partition_order--;
544
Josh Coalsonf12edc62002-10-11 06:24:33 +0000545 FLAC__ASSERT(
546 (max_rice_partition_order == 0 && blocksize >= predictor_order) ||
547 (max_rice_partition_order > 0 && blocksize >> max_rice_partition_order > predictor_order)
548 );
Josh Coalsoncda4c3c2002-08-17 15:21:29 +0000549
550 return max_rice_partition_order;
551}
552
Josh Coalsona37ba462002-08-19 21:36:39 +0000553void FLAC__format_entropy_coding_method_partitioned_rice_contents_init(FLAC__EntropyCodingMethod_PartitionedRiceContents *object)
Josh Coalsoncda4c3c2002-08-17 15:21:29 +0000554{
555 FLAC__ASSERT(0 != object);
556
Josh Coalsoncda4c3c2002-08-17 15:21:29 +0000557 object->parameters = 0;
558 object->raw_bits = 0;
559 object->capacity_by_order = 0;
560}
561
Josh Coalsona37ba462002-08-19 21:36:39 +0000562void FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(FLAC__EntropyCodingMethod_PartitionedRiceContents *object)
Josh Coalsoncda4c3c2002-08-17 15:21:29 +0000563{
564 FLAC__ASSERT(0 != object);
565
566 if(0 != object->parameters)
567 free(object->parameters);
568 if(0 != object->raw_bits)
569 free(object->raw_bits);
Josh Coalsona37ba462002-08-19 21:36:39 +0000570 FLAC__format_entropy_coding_method_partitioned_rice_contents_init(object);
Josh Coalsoncda4c3c2002-08-17 15:21:29 +0000571}
572
Josh Coalsona37ba462002-08-19 21:36:39 +0000573FLAC__bool FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(FLAC__EntropyCodingMethod_PartitionedRiceContents *object, unsigned max_partition_order)
Josh Coalsoncda4c3c2002-08-17 15:21:29 +0000574{
575 FLAC__ASSERT(0 != object);
576
577 FLAC__ASSERT(object->capacity_by_order > 0 || (0 == object->parameters && 0 == object->raw_bits));
578
579 if(object->capacity_by_order < max_partition_order) {
Erik de Castro Lopod9ae5e92015-08-22 19:22:50 +1000580 if(0 == (object->parameters = safe_realloc_(object->parameters, sizeof(unsigned)*(1 << max_partition_order))))
Josh Coalsoncda4c3c2002-08-17 15:21:29 +0000581 return false;
Erik de Castro Lopod9ae5e92015-08-22 19:22:50 +1000582 if(0 == (object->raw_bits = safe_realloc_(object->raw_bits, sizeof(unsigned)*(1 << max_partition_order))))
Josh Coalsoncda4c3c2002-08-17 15:21:29 +0000583 return false;
Josh Coalsonb47ab0d2007-06-16 00:50:28 +0000584 memset(object->raw_bits, 0, sizeof(unsigned)*(1 << max_partition_order));
Josh Coalsoncda4c3c2002-08-17 15:21:29 +0000585 object->capacity_by_order = max_partition_order;
586 }
587
588 return true;
589}