blob: da341ad56e5457f3796cba71825f5d4ec5556f64 [file] [log] [blame]
Josh Coalson26560dd2001-02-08 00:38:41 +00001/* libFLAC - Free Lossless Audio Codec library
Josh Coalsone74bd952007-02-02 06:58:19 +00002 * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
Josh Coalsonbb7f6b92000-12-10 04:09:52 +00003 *
Josh Coalsonafd81072003-01-31 23:34:56 +00004 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
Josh Coalsonbb7f6b92000-12-10 04:09:52 +00007 *
Josh Coalsonafd81072003-01-31 23:34:56 +00008 * - Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000010 *
Josh Coalsonafd81072003-01-31 23:34:56 +000011 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * - Neither the name of the Xiph.org Foundation nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000030 */
31
Josh Coalsonb1ec7962006-05-24 04:41:36 +000032#if HAVE_CONFIG_H
33# include <config.h>
34#endif
35
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000036#include <stdio.h>
Josh Coalson5a5de732002-08-01 06:37:11 +000037#include <stdlib.h> /* for qsort() */
Josh Coalson0d36cbd2002-07-15 05:24:56 +000038#include "FLAC/assert.h"
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000039#include "FLAC/format.h"
Josh Coalsoncda4c3c2002-08-17 15:21:29 +000040#include "private/format.h"
41
Josh Coalson14b184c2007-03-12 05:08:21 +000042#ifndef FLaC__INLINE
43#define FLaC__INLINE
44#endif
45
Josh Coalsoncda4c3c2002-08-17 15:21:29 +000046#ifdef min
47#undef min
48#endif
49#define min(a,b) ((a)<(b)?(a):(b))
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000050
Josh Coalson49623ea2004-07-29 06:28:59 +000051/* adjust for compilers that can't understand using LLU suffix for uint64_t literals */
52#ifdef _MSC_VER
53#define FLAC__U64L(x) x
54#else
55#define FLAC__U64L(x) x##LLU
56#endif
57
Josh Coalson82738b32002-09-25 06:09:47 +000058/* VERSION should come from configure */
Josh Coalson6afed9f2002-10-16 22:29:47 +000059FLAC_API const char *FLAC__VERSION_STRING = VERSION;
Josh Coalson82738b32002-09-25 06:09:47 +000060
Josh Coalson7581d122006-11-20 07:19:15 +000061#if defined _MSC_VER || defined __BORLANDC__ || defined __MINW32__
Josh Coalson0aad38b2002-09-09 05:06:51 +000062/* yet one more hack because of MSVC6: */
Josh Coalson826a0a72007-02-14 05:57:23 +000063FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC 1.1.4 20070213";
Josh Coalson0aad38b2002-09-09 05:06:51 +000064#else
Josh Coalson826a0a72007-02-14 05:57:23 +000065FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC " VERSION " 20070213";
Josh Coalson0aad38b2002-09-09 05:06:51 +000066#endif
67
Josh Coalson6afed9f2002-10-16 22:29:47 +000068FLAC_API const FLAC__byte FLAC__STREAM_SYNC_STRING[4] = { 'f','L','a','C' };
69FLAC_API const unsigned FLAC__STREAM_SYNC = 0x664C6143;
Josh Coalson38892872005-08-31 00:18:18 +000070FLAC_API const unsigned FLAC__STREAM_SYNC_LEN = 32; /* bits */
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000071
Josh Coalson6afed9f2002-10-16 22:29:47 +000072FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN = 16; /* bits */
73FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN = 16; /* bits */
74FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN = 24; /* bits */
75FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN = 24; /* bits */
76FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN = 20; /* bits */
77FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN = 3; /* bits */
78FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN = 5; /* bits */
79FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN = 36; /* bits */
80FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN = 128; /* bits */
Josh Coalson20135722001-02-23 21:05:53 +000081
Josh Coalson6afed9f2002-10-16 22:29:47 +000082FLAC_API const unsigned FLAC__STREAM_METADATA_APPLICATION_ID_LEN = 32; /* bits */
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000083
Josh Coalson6afed9f2002-10-16 22:29:47 +000084FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN = 64; /* bits */
85FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN = 64; /* bits */
86FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN = 16; /* bits */
Josh Coalsonc5d08e02001-04-10 19:13:50 +000087
Josh Coalson49623ea2004-07-29 06:28:59 +000088FLAC_API const FLAC__uint64 FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER = FLAC__U64L(0xffffffffffffffff);
Josh Coalson167658a2001-04-13 18:22:25 +000089
Josh Coalson6afed9f2002-10-16 22:29:47 +000090FLAC_API const unsigned FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN = 32; /* bits */
91FLAC_API const unsigned FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN = 32; /* bits */
Josh Coalsoncc059bc2002-05-04 17:35:51 +000092
Josh Coalson8e9c4512002-11-14 05:00:24 +000093FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN = 64; /* bits */
94FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN = 8; /* bits */
Josh Coalsonb3538c82003-01-12 08:42:23 +000095FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN = 3*8; /* bits */
Josh Coalson8e9c4512002-11-14 05:00:24 +000096
97FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN = 64; /* bits */
98FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN = 8; /* bits */
99FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN = 12*8; /* bits */
100FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN = 1; /* bit */
101FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN = 1; /* bit */
Josh Coalsonb3538c82003-01-12 08:42:23 +0000102FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN = 6+13*8; /* bits */
Josh Coalson8e9c4512002-11-14 05:00:24 +0000103FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN = 8; /* bits */
104
105FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN = 128*8; /* bits */
106FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN = 64; /* bits */
Josh Coalson8f0c71b2002-12-05 06:37:46 +0000107FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN = 1; /* bit */
Josh Coalsonb3538c82003-01-12 08:42:23 +0000108FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN = 7+258*8; /* bits */
Josh Coalson8e9c4512002-11-14 05:00:24 +0000109FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN = 8; /* bits */
110
Josh Coalsone343ab22006-09-23 19:21:19 +0000111FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_TYPE_LEN = 32; /* bits */
112FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN = 32; /* bits */
113FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN = 32; /* bits */
114FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN = 32; /* bits */
115FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN = 32; /* bits */
116FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN = 32; /* bits */
Josh Coalson74ed2942006-09-23 23:15:05 +0000117FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_COLORS_LEN = 32; /* bits */
Josh Coalsone343ab22006-09-23 19:21:19 +0000118FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN = 32; /* bits */
119
Josh Coalson6afed9f2002-10-16 22:29:47 +0000120FLAC_API const unsigned FLAC__STREAM_METADATA_IS_LAST_LEN = 1; /* bits */
121FLAC_API const unsigned FLAC__STREAM_METADATA_TYPE_LEN = 7; /* bits */
122FLAC_API const unsigned FLAC__STREAM_METADATA_LENGTH_LEN = 24; /* bits */
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000123
Josh Coalson6afed9f2002-10-16 22:29:47 +0000124FLAC_API const unsigned FLAC__FRAME_HEADER_SYNC = 0x3ffe;
125FLAC_API const unsigned FLAC__FRAME_HEADER_SYNC_LEN = 14; /* bits */
126FLAC_API const unsigned FLAC__FRAME_HEADER_RESERVED_LEN = 2; /* bits */
127FLAC_API const unsigned FLAC__FRAME_HEADER_BLOCK_SIZE_LEN = 4; /* bits */
128FLAC_API const unsigned FLAC__FRAME_HEADER_SAMPLE_RATE_LEN = 4; /* bits */
129FLAC_API const unsigned FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN = 4; /* bits */
130FLAC_API const unsigned FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN = 3; /* bits */
131FLAC_API const unsigned FLAC__FRAME_HEADER_ZERO_PAD_LEN = 1; /* bits */
132FLAC_API const unsigned FLAC__FRAME_HEADER_CRC_LEN = 8; /* bits */
Josh Coalson215af572001-03-27 01:15:58 +0000133
Josh Coalson6afed9f2002-10-16 22:29:47 +0000134FLAC_API const unsigned FLAC__FRAME_FOOTER_CRC_LEN = 16; /* bits */
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000135
Josh Coalson6afed9f2002-10-16 22:29:47 +0000136FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_TYPE_LEN = 2; /* bits */
137FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN = 4; /* bits */
138FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN = 4; /* bits */
139FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN = 5; /* bits */
Josh Coalson2051dd42001-04-12 22:22:34 +0000140
Josh Coalson6afed9f2002-10-16 22:29:47 +0000141FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER = 15; /* == (1<<FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN)-1 */
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000142
Josh Coalson6afed9f2002-10-16 22:29:47 +0000143FLAC_API const char * const FLAC__EntropyCodingMethodTypeString[] = {
Josh Coalson75d0a0b2001-01-24 00:42:16 +0000144 "PARTITIONED_RICE"
145};
146
Josh Coalson6afed9f2002-10-16 22:29:47 +0000147FLAC_API const unsigned FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN = 4; /* bits */
148FLAC_API const unsigned FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN = 5; /* bits */
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000149
Josh Coalson6afed9f2002-10-16 22:29:47 +0000150FLAC_API const unsigned FLAC__SUBFRAME_ZERO_PAD_LEN = 1; /* bits */
151FLAC_API const unsigned FLAC__SUBFRAME_TYPE_LEN = 6; /* bits */
152FLAC_API const unsigned FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN = 1; /* bits */
Josh Coalson215af572001-03-27 01:15:58 +0000153
Josh Coalson6afed9f2002-10-16 22:29:47 +0000154FLAC_API const unsigned FLAC__SUBFRAME_TYPE_CONSTANT_BYTE_ALIGNED_MASK = 0x00;
155FLAC_API const unsigned FLAC__SUBFRAME_TYPE_VERBATIM_BYTE_ALIGNED_MASK = 0x02;
156FLAC_API const unsigned FLAC__SUBFRAME_TYPE_FIXED_BYTE_ALIGNED_MASK = 0x10;
157FLAC_API const unsigned FLAC__SUBFRAME_TYPE_LPC_BYTE_ALIGNED_MASK = 0x40;
Josh Coalson75d0a0b2001-01-24 00:42:16 +0000158
Josh Coalson6afed9f2002-10-16 22:29:47 +0000159FLAC_API const char * const FLAC__SubframeTypeString[] = {
Josh Coalson75d0a0b2001-01-24 00:42:16 +0000160 "CONSTANT",
161 "VERBATIM",
162 "FIXED",
163 "LPC"
164};
165
Josh Coalson6afed9f2002-10-16 22:29:47 +0000166FLAC_API const char * const FLAC__ChannelAssignmentString[] = {
Josh Coalson75d0a0b2001-01-24 00:42:16 +0000167 "INDEPENDENT",
168 "LEFT_SIDE",
169 "RIGHT_SIDE",
170 "MID_SIDE"
171};
172
Josh Coalson6afed9f2002-10-16 22:29:47 +0000173FLAC_API const char * const FLAC__FrameNumberTypeString[] = {
Josh Coalson96084632001-07-16 18:07:12 +0000174 "FRAME_NUMBER_TYPE_FRAME_NUMBER",
175 "FRAME_NUMBER_TYPE_SAMPLE_NUMBER"
176};
177
Josh Coalson6afed9f2002-10-16 22:29:47 +0000178FLAC_API const char * const FLAC__MetadataTypeString[] = {
Josh Coalson20135722001-02-23 21:05:53 +0000179 "STREAMINFO",
180 "PADDING",
Josh Coalson9b04be72001-06-14 18:57:53 +0000181 "APPLICATION",
Josh Coalson7e19b542002-04-25 05:53:09 +0000182 "SEEKTABLE",
Josh Coalsone4869382002-11-15 05:41:48 +0000183 "VORBIS_COMMENT",
Josh Coalsone343ab22006-09-23 19:21:19 +0000184 "CUESHEET",
185 "PICTURE"
186};
187
188FLAC_API const char * const FLAC__StreamMetadata_Picture_TypeString[] = {
189 "Other",
190 "32x32 pixels 'file icon' (PNG only)",
191 "Other file icon",
192 "Cover (front)",
193 "Cover (back)",
194 "Leaflet page",
195 "Media (e.g. label side of CD)",
196 "Lead artist/lead performer/soloist",
197 "Artist/performer",
198 "Conductor",
199 "Band/Orchestra",
200 "Composer",
201 "Lyricist/text writer",
202 "Recording Location",
203 "During recording",
204 "During performance",
205 "Movie/video screen capture",
206 "A bright coloured fish",
207 "Illustration",
208 "Band/artist logotype",
209 "Publisher/Studio logotype"
Josh Coalson75d0a0b2001-01-24 00:42:16 +0000210};
Josh Coalsoncc059bc2002-05-04 17:35:51 +0000211
Josh Coalson6afed9f2002-10-16 22:29:47 +0000212FLAC_API FLAC__bool FLAC__format_sample_rate_is_valid(unsigned sample_rate)
Josh Coalsoncc059bc2002-05-04 17:35:51 +0000213{
214 if(
215 sample_rate == 0 ||
216 sample_rate > FLAC__MAX_SAMPLE_RATE ||
217 (
Josh Coalson765ff502002-08-27 05:46:11 +0000218 sample_rate >= (1u << 16) &&
Josh Coalsoncc059bc2002-05-04 17:35:51 +0000219 !(sample_rate % 1000 == 0 || sample_rate % 10 == 0)
220 )
221 ) {
222 return false;
223 }
224 else
225 return true;
226}
Josh Coalson0d36cbd2002-07-15 05:24:56 +0000227
Josh Coalson6afed9f2002-10-16 22:29:47 +0000228FLAC_API FLAC__bool FLAC__format_seektable_is_legal(const FLAC__StreamMetadata_SeekTable *seek_table)
Josh Coalson0d36cbd2002-07-15 05:24:56 +0000229{
230 unsigned i;
231 FLAC__uint64 prev_sample_number = 0;
232 FLAC__bool got_prev = false;
233
234 FLAC__ASSERT(0 != seek_table);
235
236 for(i = 0; i < seek_table->num_points; i++) {
237 if(got_prev) {
Josh Coalson5a5de732002-08-01 06:37:11 +0000238 if(
239 seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER &&
240 seek_table->points[i].sample_number <= prev_sample_number
241 )
Josh Coalson0d36cbd2002-07-15 05:24:56 +0000242 return false;
243 }
244 prev_sample_number = seek_table->points[i].sample_number;
245 got_prev = true;
246 }
247
248 return true;
249}
Josh Coalson5a5de732002-08-01 06:37:11 +0000250
251/* used as the sort predicate for qsort() */
252static int seekpoint_compare_(const FLAC__StreamMetadata_SeekPoint *l, const FLAC__StreamMetadata_SeekPoint *r)
253{
254 /* we don't just 'return l->sample_number - r->sample_number' since the result (FLAC__int64) might overflow an 'int' */
255 if(l->sample_number == r->sample_number)
256 return 0;
257 else if(l->sample_number < r->sample_number)
258 return -1;
259 else
260 return 1;
261}
262
Josh Coalson6afed9f2002-10-16 22:29:47 +0000263FLAC_API unsigned FLAC__format_seektable_sort(FLAC__StreamMetadata_SeekTable *seek_table)
Josh Coalson5a5de732002-08-01 06:37:11 +0000264{
265 unsigned i, j;
266 FLAC__bool first;
267
Josh Coalsona0ac09a2002-08-16 05:40:16 +0000268 FLAC__ASSERT(0 != seek_table);
269
Josh Coalson5a5de732002-08-01 06:37:11 +0000270 /* sort the seekpoints */
271 qsort(seek_table->points, seek_table->num_points, sizeof(FLAC__StreamMetadata_SeekPoint), (int (*)(const void *, const void *))seekpoint_compare_);
272
273 /* uniquify the seekpoints */
274 first = true;
275 for(i = j = 0; i < seek_table->num_points; i++) {
276 if(seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER) {
277 if(!first) {
278 if(seek_table->points[i].sample_number == seek_table->points[j-1].sample_number)
279 continue;
280 }
281 }
282 first = false;
283 seek_table->points[j++] = seek_table->points[i];
284 }
285
Josh Coalson08a62822002-08-01 07:33:36 +0000286 for(i = j; i < seek_table->num_points; i++) {
287 seek_table->points[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
288 seek_table->points[i].stream_offset = 0;
289 seek_table->points[i].frame_samples = 0;
Josh Coalson5a5de732002-08-01 06:37:11 +0000290 }
291
292 return j;
293}
Josh Coalsoncda4c3c2002-08-17 15:21:29 +0000294
Josh Coalsonf2a8e062005-08-24 07:37:11 +0000295/*
296 * also disallows non-shortest-form encodings, c.f.
297 * http://www.unicode.org/versions/corrigendum1.html
298 * and a more clear explanation at the end of this section:
299 * http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
300 */
Josh Coalson14b184c2007-03-12 05:08:21 +0000301static FLaC__INLINE unsigned utf8len_(const FLAC__byte *utf8)
Josh Coalson2de11242004-12-30 03:41:19 +0000302{
303 FLAC__ASSERT(0 != utf8);
Josh Coalsonf2a8e062005-08-24 07:37:11 +0000304 if ((utf8[0] & 0x80) == 0) {
Josh Coalson2de11242004-12-30 03:41:19 +0000305 return 1;
Josh Coalsonf2a8e062005-08-24 07:37:11 +0000306 }
307 else if ((utf8[0] & 0xE0) == 0xC0 && (utf8[1] & 0xC0) == 0x80) {
Josh Coalsonc6e53da2005-08-25 00:22:06 +0000308 if ((utf8[0] & 0xFE) == 0xC0) /* overlong sequence check */
Josh Coalsonf2a8e062005-08-24 07:37:11 +0000309 return 0;
Josh Coalson2de11242004-12-30 03:41:19 +0000310 return 2;
Josh Coalsonf2a8e062005-08-24 07:37:11 +0000311 }
312 else if ((utf8[0] & 0xF0) == 0xE0 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80) {
313 if (utf8[0] == 0xE0 && (utf8[1] & 0xE0) == 0x80) /* overlong sequence check */
314 return 0;
315 /* illegal surrogates check (U+D800...U+DFFF and U+FFFE...U+FFFF) */
316 if (utf8[0] == 0xED && (utf8[1] & 0xE0) == 0xA0) /* D800-DFFF */
317 return 0;
318 if (utf8[0] == 0xEF && utf8[1] == 0xBF && (utf8[2] & 0xFE) == 0xBE) /* FFFE-FFFF */
319 return 0;
Josh Coalson2de11242004-12-30 03:41:19 +0000320 return 3;
Josh Coalsonf2a8e062005-08-24 07:37:11 +0000321 }
322 else if ((utf8[0] & 0xF8) == 0xF0 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80) {
323 if (utf8[0] == 0xF0 && (utf8[1] & 0xF0) == 0x80) /* overlong sequence check */
324 return 0;
325 return 4;
326 }
327 else if ((utf8[0] & 0xFC) == 0xF8 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80 && (utf8[4] & 0xC0) == 0x80) {
328 if (utf8[0] == 0xF8 && (utf8[1] & 0xF8) == 0x80) /* overlong sequence check */
329 return 0;
330 return 5;
331 }
332 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) {
333 if (utf8[0] == 0xFC && (utf8[1] & 0xFC) == 0x80) /* overlong sequence check */
334 return 0;
335 return 6;
336 }
337 else {
Josh Coalson2de11242004-12-30 03:41:19 +0000338 return 0;
Josh Coalsonf2a8e062005-08-24 07:37:11 +0000339 }
Josh Coalson2de11242004-12-30 03:41:19 +0000340}
341
342FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_name_is_legal(const char *name)
343{
344 char c;
345 for(c = *name; c; c = *(++name))
346 if(c < 0x20 || c == 0x3d || c > 0x7d)
347 return false;
348 return true;
349}
350
351FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_value_is_legal(const FLAC__byte *value, unsigned length)
352{
353 if(length == (unsigned)(-1)) {
354 while(*value) {
355 unsigned n = utf8len_(value);
356 if(n == 0)
357 return false;
358 value += n;
359 }
360 }
361 else {
362 const FLAC__byte *end = value + length;
363 while(value < end) {
364 unsigned n = utf8len_(value);
365 if(n == 0)
366 return false;
367 value += n;
368 }
369 if(value != end)
370 return false;
371 }
372 return true;
373}
374
375FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_is_legal(const FLAC__byte *entry, unsigned length)
376{
377 const FLAC__byte *s, *end;
378
379 for(s = entry, end = s + length; s < end && *s != '='; s++) {
380 if(*s < 0x20 || *s > 0x7D)
381 return false;
382 }
383 if(s == end)
384 return false;
385
386 s++; /* skip '=' */
387
388 while(s < end) {
389 unsigned n = utf8len_(s);
390 if(n == 0)
391 return false;
392 s += n;
393 }
394 if(s != end)
395 return false;
396
397 return true;
398}
399
Josh Coalson8e9c4512002-11-14 05:00:24 +0000400FLAC_API FLAC__bool FLAC__format_cuesheet_is_legal(const FLAC__StreamMetadata_CueSheet *cue_sheet, FLAC__bool check_cd_da_subset, const char **violation)
401{
402 unsigned i, j;
403
404 if(check_cd_da_subset) {
405 if(cue_sheet->lead_in < 2 * 44100) {
406 if(violation) *violation = "CD-DA cue sheet must have a lead-in length of at least 2 seconds";
407 return false;
408 }
409 if(cue_sheet->lead_in % 588 != 0) {
410 if(violation) *violation = "CD-DA cue sheet lead-in length must be evenly divisible by 588 samples";
411 return false;
412 }
413 }
414
415 if(cue_sheet->num_tracks == 0) {
416 if(violation) *violation = "cue sheet must have at least one track (the lead-out)";
417 return false;
418 }
419
420 if(check_cd_da_subset && cue_sheet->tracks[cue_sheet->num_tracks-1].number != 170) {
421 if(violation) *violation = "CD-DA cue sheet must have a lead-out track number 170 (0xAA)";
422 return false;
423 }
424
425 for(i = 0; i < cue_sheet->num_tracks; i++) {
426 if(cue_sheet->tracks[i].number == 0) {
427 if(violation) *violation = "cue sheet may not have a track number 0";
428 return false;
429 }
430
431 if(check_cd_da_subset) {
432 if(!((cue_sheet->tracks[i].number >= 1 && cue_sheet->tracks[i].number <= 99) || cue_sheet->tracks[i].number == 170)) {
433 if(violation) *violation = "CD-DA cue sheet track number must be 1-99 or 170";
434 return false;
435 }
436 }
437
438 if(check_cd_da_subset && cue_sheet->tracks[i].offset % 588 != 0) {
Josh Coalsonf2a8e062005-08-24 07:37:11 +0000439 if(violation) {
Josh Coalsonfe1d3112005-08-24 00:14:23 +0000440 if(i == cue_sheet->num_tracks-1) /* the lead-out track... */
441 *violation = "CD-DA cue sheet lead-out offset must be evenly divisible by 588 samples";
442 else
443 *violation = "CD-DA cue sheet track offset must be evenly divisible by 588 samples";
Josh Coalsonf2a8e062005-08-24 07:37:11 +0000444 }
Josh Coalson8e9c4512002-11-14 05:00:24 +0000445 return false;
446 }
447
Josh Coalson3f86cc72002-11-21 06:41:46 +0000448 if(i < cue_sheet->num_tracks - 1) {
449 if(cue_sheet->tracks[i].num_indices == 0) {
450 if(violation) *violation = "cue sheet track must have at least one index point";
451 return false;
452 }
Josh Coalson8e9c4512002-11-14 05:00:24 +0000453
Josh Coalson3f86cc72002-11-21 06:41:46 +0000454 if(cue_sheet->tracks[i].indices[0].number > 1) {
455 if(violation) *violation = "cue sheet track's first index number must be 0 or 1";
456 return false;
457 }
Josh Coalson8e9c4512002-11-14 05:00:24 +0000458 }
459
460 for(j = 0; j < cue_sheet->tracks[i].num_indices; j++) {
461 if(check_cd_da_subset && cue_sheet->tracks[i].indices[j].offset % 588 != 0) {
462 if(violation) *violation = "CD-DA cue sheet track index offset must be evenly divisible by 588 samples";
463 return false;
464 }
465
466 if(j > 0) {
467 if(cue_sheet->tracks[i].indices[j].number != cue_sheet->tracks[i].indices[j-1].number + 1) {
468 if(violation) *violation = "cue sheet track index numbers must increase by 1";
469 return false;
470 }
471 }
472 }
473 }
474
475 return true;
476}
477
Josh Coalsone343ab22006-09-23 19:21:19 +0000478FLAC_API FLAC__bool FLAC__format_picture_is_legal(const FLAC__StreamMetadata_Picture *picture, const char **violation)
479{
480 char *p;
481 FLAC__byte *b;
482
483 for(p = picture->mime_type; *p; p++) {
484 if(*p < 0x20 || *p > 0x7e) {
485 if(violation) *violation = "MIME type string must contain only printable ASCII characters (0x20-0x7e)";
486 return false;
487 }
488 }
489
490 for(b = picture->description; *b; ) {
491 unsigned n = utf8len_(b);
492 if(n == 0) {
493 if(violation) *violation = "description string must be valid UTF-8";
494 return false;
495 }
496 b += n;
497 }
498
499 return true;
500}
501
Josh Coalson8e9c4512002-11-14 05:00:24 +0000502/*
503 * These routines are private to libFLAC
504 */
Josh Coalsoncda4c3c2002-08-17 15:21:29 +0000505unsigned FLAC__format_get_max_rice_partition_order(unsigned blocksize, unsigned predictor_order)
506{
507 return
508 FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(
509 FLAC__format_get_max_rice_partition_order_from_blocksize(blocksize),
510 blocksize,
511 predictor_order
512 );
513}
514
515unsigned FLAC__format_get_max_rice_partition_order_from_blocksize(unsigned blocksize)
516{
517 unsigned max_rice_partition_order = 0;
518 while(!(blocksize & 1)) {
519 max_rice_partition_order++;
520 blocksize >>= 1;
521 }
522 return min(FLAC__MAX_RICE_PARTITION_ORDER, max_rice_partition_order);
523}
524
525unsigned FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(unsigned limit, unsigned blocksize, unsigned predictor_order)
526{
527 unsigned max_rice_partition_order = limit;
528
529 while(max_rice_partition_order > 0 && (blocksize >> max_rice_partition_order) <= predictor_order)
530 max_rice_partition_order--;
531
Josh Coalsonf12edc62002-10-11 06:24:33 +0000532 FLAC__ASSERT(
533 (max_rice_partition_order == 0 && blocksize >= predictor_order) ||
534 (max_rice_partition_order > 0 && blocksize >> max_rice_partition_order > predictor_order)
535 );
Josh Coalsoncda4c3c2002-08-17 15:21:29 +0000536
537 return max_rice_partition_order;
538}
539
Josh Coalsona37ba462002-08-19 21:36:39 +0000540void FLAC__format_entropy_coding_method_partitioned_rice_contents_init(FLAC__EntropyCodingMethod_PartitionedRiceContents *object)
Josh Coalsoncda4c3c2002-08-17 15:21:29 +0000541{
542 FLAC__ASSERT(0 != object);
543
Josh Coalsoncda4c3c2002-08-17 15:21:29 +0000544 object->parameters = 0;
545 object->raw_bits = 0;
546 object->capacity_by_order = 0;
547}
548
Josh Coalsona37ba462002-08-19 21:36:39 +0000549void FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(FLAC__EntropyCodingMethod_PartitionedRiceContents *object)
Josh Coalsoncda4c3c2002-08-17 15:21:29 +0000550{
551 FLAC__ASSERT(0 != object);
552
553 if(0 != object->parameters)
554 free(object->parameters);
555 if(0 != object->raw_bits)
556 free(object->raw_bits);
Josh Coalsona37ba462002-08-19 21:36:39 +0000557 FLAC__format_entropy_coding_method_partitioned_rice_contents_init(object);
Josh Coalsoncda4c3c2002-08-17 15:21:29 +0000558}
559
Josh Coalsona37ba462002-08-19 21:36:39 +0000560FLAC__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 +0000561{
562 FLAC__ASSERT(0 != object);
563
564 FLAC__ASSERT(object->capacity_by_order > 0 || (0 == object->parameters && 0 == object->raw_bits));
565
566 if(object->capacity_by_order < max_partition_order) {
Josh Coalson5e3fcb22002-11-06 07:11:26 +0000567 if(0 == (object->parameters = (unsigned*)realloc(object->parameters, sizeof(unsigned)*(1 << max_partition_order))))
Josh Coalsoncda4c3c2002-08-17 15:21:29 +0000568 return false;
Josh Coalson5e3fcb22002-11-06 07:11:26 +0000569 if(0 == (object->raw_bits = (unsigned*)realloc(object->raw_bits, sizeof(unsigned)*(1 << max_partition_order))))
Josh Coalsoncda4c3c2002-08-17 15:21:29 +0000570 return false;
571 object->capacity_by_order = max_partition_order;
572 }
573
574 return true;
575}