blob: 46ac754ebae8313f5af35b3e044ddca7d0c44897 [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
42#ifdef min
43#undef min
44#endif
45#define min(a,b) ((a)<(b)?(a):(b))
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000046
Josh Coalson49623ea2004-07-29 06:28:59 +000047/* adjust for compilers that can't understand using LLU suffix for uint64_t literals */
48#ifdef _MSC_VER
49#define FLAC__U64L(x) x
50#else
51#define FLAC__U64L(x) x##LLU
52#endif
53
Josh Coalson82738b32002-09-25 06:09:47 +000054/* VERSION should come from configure */
Josh Coalson6afed9f2002-10-16 22:29:47 +000055FLAC_API const char *FLAC__VERSION_STRING = VERSION;
Josh Coalson82738b32002-09-25 06:09:47 +000056
Josh Coalson7581d122006-11-20 07:19:15 +000057#if defined _MSC_VER || defined __BORLANDC__ || defined __MINW32__
Josh Coalson0aad38b2002-09-09 05:06:51 +000058/* yet one more hack because of MSVC6: */
Josh Coalsonfc92d8d2007-02-02 06:18:51 +000059FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC 1.1.4-alpha1 20070201";
Josh Coalson0aad38b2002-09-09 05:06:51 +000060#else
Josh Coalsonfc92d8d2007-02-02 06:18:51 +000061FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC " VERSION " 20070201";
Josh Coalson0aad38b2002-09-09 05:06:51 +000062#endif
63
Josh Coalson6afed9f2002-10-16 22:29:47 +000064FLAC_API const FLAC__byte FLAC__STREAM_SYNC_STRING[4] = { 'f','L','a','C' };
65FLAC_API const unsigned FLAC__STREAM_SYNC = 0x664C6143;
Josh Coalson38892872005-08-31 00:18:18 +000066FLAC_API const unsigned FLAC__STREAM_SYNC_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_STREAMINFO_MIN_BLOCK_SIZE_LEN = 16; /* bits */
69FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN = 16; /* bits */
70FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN = 24; /* bits */
71FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN = 24; /* bits */
72FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN = 20; /* bits */
73FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN = 3; /* bits */
74FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN = 5; /* bits */
75FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN = 36; /* bits */
76FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN = 128; /* bits */
Josh Coalson20135722001-02-23 21:05:53 +000077
Josh Coalson6afed9f2002-10-16 22:29:47 +000078FLAC_API const unsigned FLAC__STREAM_METADATA_APPLICATION_ID_LEN = 32; /* bits */
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000079
Josh Coalson6afed9f2002-10-16 22:29:47 +000080FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN = 64; /* bits */
81FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN = 64; /* bits */
82FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN = 16; /* bits */
Josh Coalsonc5d08e02001-04-10 19:13:50 +000083
Josh Coalson49623ea2004-07-29 06:28:59 +000084FLAC_API const FLAC__uint64 FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER = FLAC__U64L(0xffffffffffffffff);
Josh Coalson167658a2001-04-13 18:22:25 +000085
Josh Coalson6afed9f2002-10-16 22:29:47 +000086FLAC_API const unsigned FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN = 32; /* bits */
87FLAC_API const unsigned FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN = 32; /* bits */
Josh Coalsoncc059bc2002-05-04 17:35:51 +000088
Josh Coalson8e9c4512002-11-14 05:00:24 +000089FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN = 64; /* bits */
90FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN = 8; /* bits */
Josh Coalsonb3538c82003-01-12 08:42:23 +000091FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN = 3*8; /* bits */
Josh Coalson8e9c4512002-11-14 05:00:24 +000092
93FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN = 64; /* bits */
94FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN = 8; /* bits */
95FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN = 12*8; /* bits */
96FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN = 1; /* bit */
97FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN = 1; /* bit */
Josh Coalsonb3538c82003-01-12 08:42:23 +000098FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN = 6+13*8; /* bits */
Josh Coalson8e9c4512002-11-14 05:00:24 +000099FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN = 8; /* bits */
100
101FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN = 128*8; /* bits */
102FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN = 64; /* bits */
Josh Coalson8f0c71b2002-12-05 06:37:46 +0000103FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN = 1; /* bit */
Josh Coalsonb3538c82003-01-12 08:42:23 +0000104FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN = 7+258*8; /* bits */
Josh Coalson8e9c4512002-11-14 05:00:24 +0000105FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN = 8; /* bits */
106
Josh Coalsone343ab22006-09-23 19:21:19 +0000107FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_TYPE_LEN = 32; /* bits */
108FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN = 32; /* bits */
109FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN = 32; /* bits */
110FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN = 32; /* bits */
111FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN = 32; /* bits */
112FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN = 32; /* bits */
Josh Coalson74ed2942006-09-23 23:15:05 +0000113FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_COLORS_LEN = 32; /* bits */
Josh Coalsone343ab22006-09-23 19:21:19 +0000114FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN = 32; /* bits */
115
Josh Coalson6afed9f2002-10-16 22:29:47 +0000116FLAC_API const unsigned FLAC__STREAM_METADATA_IS_LAST_LEN = 1; /* bits */
117FLAC_API const unsigned FLAC__STREAM_METADATA_TYPE_LEN = 7; /* bits */
118FLAC_API const unsigned FLAC__STREAM_METADATA_LENGTH_LEN = 24; /* bits */
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000119
Josh Coalson6afed9f2002-10-16 22:29:47 +0000120FLAC_API const unsigned FLAC__FRAME_HEADER_SYNC = 0x3ffe;
121FLAC_API const unsigned FLAC__FRAME_HEADER_SYNC_LEN = 14; /* bits */
122FLAC_API const unsigned FLAC__FRAME_HEADER_RESERVED_LEN = 2; /* bits */
123FLAC_API const unsigned FLAC__FRAME_HEADER_BLOCK_SIZE_LEN = 4; /* bits */
124FLAC_API const unsigned FLAC__FRAME_HEADER_SAMPLE_RATE_LEN = 4; /* bits */
125FLAC_API const unsigned FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN = 4; /* bits */
126FLAC_API const unsigned FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN = 3; /* bits */
127FLAC_API const unsigned FLAC__FRAME_HEADER_ZERO_PAD_LEN = 1; /* bits */
128FLAC_API const unsigned FLAC__FRAME_HEADER_CRC_LEN = 8; /* bits */
Josh Coalson215af572001-03-27 01:15:58 +0000129
Josh Coalson6afed9f2002-10-16 22:29:47 +0000130FLAC_API const unsigned FLAC__FRAME_FOOTER_CRC_LEN = 16; /* bits */
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000131
Josh Coalson6afed9f2002-10-16 22:29:47 +0000132FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_TYPE_LEN = 2; /* bits */
133FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN = 4; /* bits */
134FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN = 4; /* bits */
135FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN = 5; /* bits */
Josh Coalson2051dd42001-04-12 22:22:34 +0000136
Josh Coalson6afed9f2002-10-16 22:29:47 +0000137FLAC_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 +0000138
Josh Coalson6afed9f2002-10-16 22:29:47 +0000139FLAC_API const char * const FLAC__EntropyCodingMethodTypeString[] = {
Josh Coalson75d0a0b2001-01-24 00:42:16 +0000140 "PARTITIONED_RICE"
141};
142
Josh Coalson6afed9f2002-10-16 22:29:47 +0000143FLAC_API const unsigned FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN = 4; /* bits */
144FLAC_API const unsigned FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN = 5; /* bits */
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000145
Josh Coalson6afed9f2002-10-16 22:29:47 +0000146FLAC_API const unsigned FLAC__SUBFRAME_ZERO_PAD_LEN = 1; /* bits */
147FLAC_API const unsigned FLAC__SUBFRAME_TYPE_LEN = 6; /* bits */
148FLAC_API const unsigned FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN = 1; /* bits */
Josh Coalson215af572001-03-27 01:15:58 +0000149
Josh Coalson6afed9f2002-10-16 22:29:47 +0000150FLAC_API const unsigned FLAC__SUBFRAME_TYPE_CONSTANT_BYTE_ALIGNED_MASK = 0x00;
151FLAC_API const unsigned FLAC__SUBFRAME_TYPE_VERBATIM_BYTE_ALIGNED_MASK = 0x02;
152FLAC_API const unsigned FLAC__SUBFRAME_TYPE_FIXED_BYTE_ALIGNED_MASK = 0x10;
153FLAC_API const unsigned FLAC__SUBFRAME_TYPE_LPC_BYTE_ALIGNED_MASK = 0x40;
Josh Coalson75d0a0b2001-01-24 00:42:16 +0000154
Josh Coalson6afed9f2002-10-16 22:29:47 +0000155FLAC_API const char * const FLAC__SubframeTypeString[] = {
Josh Coalson75d0a0b2001-01-24 00:42:16 +0000156 "CONSTANT",
157 "VERBATIM",
158 "FIXED",
159 "LPC"
160};
161
Josh Coalson6afed9f2002-10-16 22:29:47 +0000162FLAC_API const char * const FLAC__ChannelAssignmentString[] = {
Josh Coalson75d0a0b2001-01-24 00:42:16 +0000163 "INDEPENDENT",
164 "LEFT_SIDE",
165 "RIGHT_SIDE",
166 "MID_SIDE"
167};
168
Josh Coalson6afed9f2002-10-16 22:29:47 +0000169FLAC_API const char * const FLAC__FrameNumberTypeString[] = {
Josh Coalson96084632001-07-16 18:07:12 +0000170 "FRAME_NUMBER_TYPE_FRAME_NUMBER",
171 "FRAME_NUMBER_TYPE_SAMPLE_NUMBER"
172};
173
Josh Coalson6afed9f2002-10-16 22:29:47 +0000174FLAC_API const char * const FLAC__MetadataTypeString[] = {
Josh Coalson20135722001-02-23 21:05:53 +0000175 "STREAMINFO",
176 "PADDING",
Josh Coalson9b04be72001-06-14 18:57:53 +0000177 "APPLICATION",
Josh Coalson7e19b542002-04-25 05:53:09 +0000178 "SEEKTABLE",
Josh Coalsone4869382002-11-15 05:41:48 +0000179 "VORBIS_COMMENT",
Josh Coalsone343ab22006-09-23 19:21:19 +0000180 "CUESHEET",
181 "PICTURE"
182};
183
184FLAC_API const char * const FLAC__StreamMetadata_Picture_TypeString[] = {
185 "Other",
186 "32x32 pixels 'file icon' (PNG only)",
187 "Other file icon",
188 "Cover (front)",
189 "Cover (back)",
190 "Leaflet page",
191 "Media (e.g. label side of CD)",
192 "Lead artist/lead performer/soloist",
193 "Artist/performer",
194 "Conductor",
195 "Band/Orchestra",
196 "Composer",
197 "Lyricist/text writer",
198 "Recording Location",
199 "During recording",
200 "During performance",
201 "Movie/video screen capture",
202 "A bright coloured fish",
203 "Illustration",
204 "Band/artist logotype",
205 "Publisher/Studio logotype"
Josh Coalson75d0a0b2001-01-24 00:42:16 +0000206};
Josh Coalsoncc059bc2002-05-04 17:35:51 +0000207
Josh Coalson6afed9f2002-10-16 22:29:47 +0000208FLAC_API FLAC__bool FLAC__format_sample_rate_is_valid(unsigned sample_rate)
Josh Coalsoncc059bc2002-05-04 17:35:51 +0000209{
210 if(
211 sample_rate == 0 ||
212 sample_rate > FLAC__MAX_SAMPLE_RATE ||
213 (
Josh Coalson765ff502002-08-27 05:46:11 +0000214 sample_rate >= (1u << 16) &&
Josh Coalsoncc059bc2002-05-04 17:35:51 +0000215 !(sample_rate % 1000 == 0 || sample_rate % 10 == 0)
216 )
217 ) {
218 return false;
219 }
220 else
221 return true;
222}
Josh Coalson0d36cbd2002-07-15 05:24:56 +0000223
Josh Coalson6afed9f2002-10-16 22:29:47 +0000224FLAC_API FLAC__bool FLAC__format_seektable_is_legal(const FLAC__StreamMetadata_SeekTable *seek_table)
Josh Coalson0d36cbd2002-07-15 05:24:56 +0000225{
226 unsigned i;
227 FLAC__uint64 prev_sample_number = 0;
228 FLAC__bool got_prev = false;
229
230 FLAC__ASSERT(0 != seek_table);
231
232 for(i = 0; i < seek_table->num_points; i++) {
233 if(got_prev) {
Josh Coalson5a5de732002-08-01 06:37:11 +0000234 if(
235 seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER &&
236 seek_table->points[i].sample_number <= prev_sample_number
237 )
Josh Coalson0d36cbd2002-07-15 05:24:56 +0000238 return false;
239 }
240 prev_sample_number = seek_table->points[i].sample_number;
241 got_prev = true;
242 }
243
244 return true;
245}
Josh Coalson5a5de732002-08-01 06:37:11 +0000246
247/* used as the sort predicate for qsort() */
248static int seekpoint_compare_(const FLAC__StreamMetadata_SeekPoint *l, const FLAC__StreamMetadata_SeekPoint *r)
249{
250 /* we don't just 'return l->sample_number - r->sample_number' since the result (FLAC__int64) might overflow an 'int' */
251 if(l->sample_number == r->sample_number)
252 return 0;
253 else if(l->sample_number < r->sample_number)
254 return -1;
255 else
256 return 1;
257}
258
Josh Coalson6afed9f2002-10-16 22:29:47 +0000259FLAC_API unsigned FLAC__format_seektable_sort(FLAC__StreamMetadata_SeekTable *seek_table)
Josh Coalson5a5de732002-08-01 06:37:11 +0000260{
261 unsigned i, j;
262 FLAC__bool first;
263
Josh Coalsona0ac09a2002-08-16 05:40:16 +0000264 FLAC__ASSERT(0 != seek_table);
265
Josh Coalson5a5de732002-08-01 06:37:11 +0000266 /* sort the seekpoints */
267 qsort(seek_table->points, seek_table->num_points, sizeof(FLAC__StreamMetadata_SeekPoint), (int (*)(const void *, const void *))seekpoint_compare_);
268
269 /* uniquify the seekpoints */
270 first = true;
271 for(i = j = 0; i < seek_table->num_points; i++) {
272 if(seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER) {
273 if(!first) {
274 if(seek_table->points[i].sample_number == seek_table->points[j-1].sample_number)
275 continue;
276 }
277 }
278 first = false;
279 seek_table->points[j++] = seek_table->points[i];
280 }
281
Josh Coalson08a62822002-08-01 07:33:36 +0000282 for(i = j; i < seek_table->num_points; i++) {
283 seek_table->points[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
284 seek_table->points[i].stream_offset = 0;
285 seek_table->points[i].frame_samples = 0;
Josh Coalson5a5de732002-08-01 06:37:11 +0000286 }
287
288 return j;
289}
Josh Coalsoncda4c3c2002-08-17 15:21:29 +0000290
Josh Coalsonf2a8e062005-08-24 07:37:11 +0000291/*
292 * also disallows non-shortest-form encodings, c.f.
293 * http://www.unicode.org/versions/corrigendum1.html
294 * and a more clear explanation at the end of this section:
295 * http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
296 */
Josh Coalson2de11242004-12-30 03:41:19 +0000297static __inline unsigned utf8len_(const FLAC__byte *utf8)
298{
299 FLAC__ASSERT(0 != utf8);
Josh Coalsonf2a8e062005-08-24 07:37:11 +0000300 if ((utf8[0] & 0x80) == 0) {
Josh Coalson2de11242004-12-30 03:41:19 +0000301 return 1;
Josh Coalsonf2a8e062005-08-24 07:37:11 +0000302 }
303 else if ((utf8[0] & 0xE0) == 0xC0 && (utf8[1] & 0xC0) == 0x80) {
Josh Coalsonc6e53da2005-08-25 00:22:06 +0000304 if ((utf8[0] & 0xFE) == 0xC0) /* overlong sequence check */
Josh Coalsonf2a8e062005-08-24 07:37:11 +0000305 return 0;
Josh Coalson2de11242004-12-30 03:41:19 +0000306 return 2;
Josh Coalsonf2a8e062005-08-24 07:37:11 +0000307 }
308 else if ((utf8[0] & 0xF0) == 0xE0 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80) {
309 if (utf8[0] == 0xE0 && (utf8[1] & 0xE0) == 0x80) /* overlong sequence check */
310 return 0;
311 /* illegal surrogates check (U+D800...U+DFFF and U+FFFE...U+FFFF) */
312 if (utf8[0] == 0xED && (utf8[1] & 0xE0) == 0xA0) /* D800-DFFF */
313 return 0;
314 if (utf8[0] == 0xEF && utf8[1] == 0xBF && (utf8[2] & 0xFE) == 0xBE) /* FFFE-FFFF */
315 return 0;
Josh Coalson2de11242004-12-30 03:41:19 +0000316 return 3;
Josh Coalsonf2a8e062005-08-24 07:37:11 +0000317 }
318 else if ((utf8[0] & 0xF8) == 0xF0 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80) {
319 if (utf8[0] == 0xF0 && (utf8[1] & 0xF0) == 0x80) /* overlong sequence check */
320 return 0;
321 return 4;
322 }
323 else if ((utf8[0] & 0xFC) == 0xF8 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80 && (utf8[4] & 0xC0) == 0x80) {
324 if (utf8[0] == 0xF8 && (utf8[1] & 0xF8) == 0x80) /* overlong sequence check */
325 return 0;
326 return 5;
327 }
328 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) {
329 if (utf8[0] == 0xFC && (utf8[1] & 0xFC) == 0x80) /* overlong sequence check */
330 return 0;
331 return 6;
332 }
333 else {
Josh Coalson2de11242004-12-30 03:41:19 +0000334 return 0;
Josh Coalsonf2a8e062005-08-24 07:37:11 +0000335 }
Josh Coalson2de11242004-12-30 03:41:19 +0000336}
337
338FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_name_is_legal(const char *name)
339{
340 char c;
341 for(c = *name; c; c = *(++name))
342 if(c < 0x20 || c == 0x3d || c > 0x7d)
343 return false;
344 return true;
345}
346
347FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_value_is_legal(const FLAC__byte *value, unsigned length)
348{
349 if(length == (unsigned)(-1)) {
350 while(*value) {
351 unsigned n = utf8len_(value);
352 if(n == 0)
353 return false;
354 value += n;
355 }
356 }
357 else {
358 const FLAC__byte *end = value + length;
359 while(value < end) {
360 unsigned n = utf8len_(value);
361 if(n == 0)
362 return false;
363 value += n;
364 }
365 if(value != end)
366 return false;
367 }
368 return true;
369}
370
371FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_is_legal(const FLAC__byte *entry, unsigned length)
372{
373 const FLAC__byte *s, *end;
374
375 for(s = entry, end = s + length; s < end && *s != '='; s++) {
376 if(*s < 0x20 || *s > 0x7D)
377 return false;
378 }
379 if(s == end)
380 return false;
381
382 s++; /* skip '=' */
383
384 while(s < end) {
385 unsigned n = utf8len_(s);
386 if(n == 0)
387 return false;
388 s += n;
389 }
390 if(s != end)
391 return false;
392
393 return true;
394}
395
Josh Coalson8e9c4512002-11-14 05:00:24 +0000396FLAC_API FLAC__bool FLAC__format_cuesheet_is_legal(const FLAC__StreamMetadata_CueSheet *cue_sheet, FLAC__bool check_cd_da_subset, const char **violation)
397{
398 unsigned i, j;
399
400 if(check_cd_da_subset) {
401 if(cue_sheet->lead_in < 2 * 44100) {
402 if(violation) *violation = "CD-DA cue sheet must have a lead-in length of at least 2 seconds";
403 return false;
404 }
405 if(cue_sheet->lead_in % 588 != 0) {
406 if(violation) *violation = "CD-DA cue sheet lead-in length must be evenly divisible by 588 samples";
407 return false;
408 }
409 }
410
411 if(cue_sheet->num_tracks == 0) {
412 if(violation) *violation = "cue sheet must have at least one track (the lead-out)";
413 return false;
414 }
415
416 if(check_cd_da_subset && cue_sheet->tracks[cue_sheet->num_tracks-1].number != 170) {
417 if(violation) *violation = "CD-DA cue sheet must have a lead-out track number 170 (0xAA)";
418 return false;
419 }
420
421 for(i = 0; i < cue_sheet->num_tracks; i++) {
422 if(cue_sheet->tracks[i].number == 0) {
423 if(violation) *violation = "cue sheet may not have a track number 0";
424 return false;
425 }
426
427 if(check_cd_da_subset) {
428 if(!((cue_sheet->tracks[i].number >= 1 && cue_sheet->tracks[i].number <= 99) || cue_sheet->tracks[i].number == 170)) {
429 if(violation) *violation = "CD-DA cue sheet track number must be 1-99 or 170";
430 return false;
431 }
432 }
433
434 if(check_cd_da_subset && cue_sheet->tracks[i].offset % 588 != 0) {
Josh Coalsonf2a8e062005-08-24 07:37:11 +0000435 if(violation) {
Josh Coalsonfe1d3112005-08-24 00:14:23 +0000436 if(i == cue_sheet->num_tracks-1) /* the lead-out track... */
437 *violation = "CD-DA cue sheet lead-out offset must be evenly divisible by 588 samples";
438 else
439 *violation = "CD-DA cue sheet track offset must be evenly divisible by 588 samples";
Josh Coalsonf2a8e062005-08-24 07:37:11 +0000440 }
Josh Coalson8e9c4512002-11-14 05:00:24 +0000441 return false;
442 }
443
Josh Coalson3f86cc72002-11-21 06:41:46 +0000444 if(i < cue_sheet->num_tracks - 1) {
445 if(cue_sheet->tracks[i].num_indices == 0) {
446 if(violation) *violation = "cue sheet track must have at least one index point";
447 return false;
448 }
Josh Coalson8e9c4512002-11-14 05:00:24 +0000449
Josh Coalson3f86cc72002-11-21 06:41:46 +0000450 if(cue_sheet->tracks[i].indices[0].number > 1) {
451 if(violation) *violation = "cue sheet track's first index number must be 0 or 1";
452 return false;
453 }
Josh Coalson8e9c4512002-11-14 05:00:24 +0000454 }
455
456 for(j = 0; j < cue_sheet->tracks[i].num_indices; j++) {
457 if(check_cd_da_subset && cue_sheet->tracks[i].indices[j].offset % 588 != 0) {
458 if(violation) *violation = "CD-DA cue sheet track index offset must be evenly divisible by 588 samples";
459 return false;
460 }
461
462 if(j > 0) {
463 if(cue_sheet->tracks[i].indices[j].number != cue_sheet->tracks[i].indices[j-1].number + 1) {
464 if(violation) *violation = "cue sheet track index numbers must increase by 1";
465 return false;
466 }
467 }
468 }
469 }
470
471 return true;
472}
473
Josh Coalsone343ab22006-09-23 19:21:19 +0000474FLAC_API FLAC__bool FLAC__format_picture_is_legal(const FLAC__StreamMetadata_Picture *picture, const char **violation)
475{
476 char *p;
477 FLAC__byte *b;
478
479 for(p = picture->mime_type; *p; p++) {
480 if(*p < 0x20 || *p > 0x7e) {
481 if(violation) *violation = "MIME type string must contain only printable ASCII characters (0x20-0x7e)";
482 return false;
483 }
484 }
485
486 for(b = picture->description; *b; ) {
487 unsigned n = utf8len_(b);
488 if(n == 0) {
489 if(violation) *violation = "description string must be valid UTF-8";
490 return false;
491 }
492 b += n;
493 }
494
495 return true;
496}
497
Josh Coalson8e9c4512002-11-14 05:00:24 +0000498/*
499 * These routines are private to libFLAC
500 */
Josh Coalsoncda4c3c2002-08-17 15:21:29 +0000501unsigned FLAC__format_get_max_rice_partition_order(unsigned blocksize, unsigned predictor_order)
502{
503 return
504 FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(
505 FLAC__format_get_max_rice_partition_order_from_blocksize(blocksize),
506 blocksize,
507 predictor_order
508 );
509}
510
511unsigned FLAC__format_get_max_rice_partition_order_from_blocksize(unsigned blocksize)
512{
513 unsigned max_rice_partition_order = 0;
514 while(!(blocksize & 1)) {
515 max_rice_partition_order++;
516 blocksize >>= 1;
517 }
518 return min(FLAC__MAX_RICE_PARTITION_ORDER, max_rice_partition_order);
519}
520
521unsigned FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(unsigned limit, unsigned blocksize, unsigned predictor_order)
522{
523 unsigned max_rice_partition_order = limit;
524
525 while(max_rice_partition_order > 0 && (blocksize >> max_rice_partition_order) <= predictor_order)
526 max_rice_partition_order--;
527
Josh Coalsonf12edc62002-10-11 06:24:33 +0000528 FLAC__ASSERT(
529 (max_rice_partition_order == 0 && blocksize >= predictor_order) ||
530 (max_rice_partition_order > 0 && blocksize >> max_rice_partition_order > predictor_order)
531 );
Josh Coalsoncda4c3c2002-08-17 15:21:29 +0000532
533 return max_rice_partition_order;
534}
535
Josh Coalsona37ba462002-08-19 21:36:39 +0000536void FLAC__format_entropy_coding_method_partitioned_rice_contents_init(FLAC__EntropyCodingMethod_PartitionedRiceContents *object)
Josh Coalsoncda4c3c2002-08-17 15:21:29 +0000537{
538 FLAC__ASSERT(0 != object);
539
Josh Coalsoncda4c3c2002-08-17 15:21:29 +0000540 object->parameters = 0;
541 object->raw_bits = 0;
542 object->capacity_by_order = 0;
543}
544
Josh Coalsona37ba462002-08-19 21:36:39 +0000545void FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(FLAC__EntropyCodingMethod_PartitionedRiceContents *object)
Josh Coalsoncda4c3c2002-08-17 15:21:29 +0000546{
547 FLAC__ASSERT(0 != object);
548
549 if(0 != object->parameters)
550 free(object->parameters);
551 if(0 != object->raw_bits)
552 free(object->raw_bits);
Josh Coalsona37ba462002-08-19 21:36:39 +0000553 FLAC__format_entropy_coding_method_partitioned_rice_contents_init(object);
Josh Coalsoncda4c3c2002-08-17 15:21:29 +0000554}
555
Josh Coalsona37ba462002-08-19 21:36:39 +0000556FLAC__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 +0000557{
558 FLAC__ASSERT(0 != object);
559
560 FLAC__ASSERT(object->capacity_by_order > 0 || (0 == object->parameters && 0 == object->raw_bits));
561
562 if(object->capacity_by_order < max_partition_order) {
Josh Coalson5e3fcb22002-11-06 07:11:26 +0000563 if(0 == (object->parameters = (unsigned*)realloc(object->parameters, sizeof(unsigned)*(1 << max_partition_order))))
Josh Coalsoncda4c3c2002-08-17 15:21:29 +0000564 return false;
Josh Coalson5e3fcb22002-11-06 07:11:26 +0000565 if(0 == (object->raw_bits = (unsigned*)realloc(object->raw_bits, sizeof(unsigned)*(1 << max_partition_order))))
Josh Coalsoncda4c3c2002-08-17 15:21:29 +0000566 return false;
567 object->capacity_by_order = max_partition_order;
568 }
569
570 return true;
571}