blob: bb5feebe4161beed8e73bb93600091e2a35d2cb5 [file] [log] [blame]
Josh Coalson26560dd2001-02-08 00:38:41 +00001/* libFLAC - Free Lossless Audio Codec library
Josh Coalson0395dac2006-04-25 06:59:33 +00002 * Copyright (C) 2000,2001,2002,2003,2004,2005,2006 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 Coalson0aad38b2002-09-09 05:06:51 +000057#if defined _MSC_VER || defined __MINW32__
58/* yet one more hack because of MSVC6: */
Josh Coalsone5ad6bd2006-08-29 03:49:38 +000059FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC 1.1.3 20060831";
Josh Coalson0aad38b2002-09-09 05:06:51 +000060#else
Josh Coalsone5ad6bd2006-08-29 03:49:38 +000061FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC " VERSION " 20060831";
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 */
113FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN = 32; /* bits */
114
Josh Coalson6afed9f2002-10-16 22:29:47 +0000115FLAC_API const unsigned FLAC__STREAM_METADATA_IS_LAST_LEN = 1; /* bits */
116FLAC_API const unsigned FLAC__STREAM_METADATA_TYPE_LEN = 7; /* bits */
117FLAC_API const unsigned FLAC__STREAM_METADATA_LENGTH_LEN = 24; /* bits */
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000118
Josh Coalson6afed9f2002-10-16 22:29:47 +0000119FLAC_API const unsigned FLAC__FRAME_HEADER_SYNC = 0x3ffe;
120FLAC_API const unsigned FLAC__FRAME_HEADER_SYNC_LEN = 14; /* bits */
121FLAC_API const unsigned FLAC__FRAME_HEADER_RESERVED_LEN = 2; /* bits */
122FLAC_API const unsigned FLAC__FRAME_HEADER_BLOCK_SIZE_LEN = 4; /* bits */
123FLAC_API const unsigned FLAC__FRAME_HEADER_SAMPLE_RATE_LEN = 4; /* bits */
124FLAC_API const unsigned FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN = 4; /* bits */
125FLAC_API const unsigned FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN = 3; /* bits */
126FLAC_API const unsigned FLAC__FRAME_HEADER_ZERO_PAD_LEN = 1; /* bits */
127FLAC_API const unsigned FLAC__FRAME_HEADER_CRC_LEN = 8; /* bits */
Josh Coalson215af572001-03-27 01:15:58 +0000128
Josh Coalson6afed9f2002-10-16 22:29:47 +0000129FLAC_API const unsigned FLAC__FRAME_FOOTER_CRC_LEN = 16; /* bits */
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000130
Josh Coalson6afed9f2002-10-16 22:29:47 +0000131FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_TYPE_LEN = 2; /* bits */
132FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN = 4; /* bits */
133FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN = 4; /* bits */
134FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN = 5; /* bits */
Josh Coalson2051dd42001-04-12 22:22:34 +0000135
Josh Coalson6afed9f2002-10-16 22:29:47 +0000136FLAC_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 +0000137
Josh Coalson6afed9f2002-10-16 22:29:47 +0000138FLAC_API const char * const FLAC__EntropyCodingMethodTypeString[] = {
Josh Coalson75d0a0b2001-01-24 00:42:16 +0000139 "PARTITIONED_RICE"
140};
141
Josh Coalson6afed9f2002-10-16 22:29:47 +0000142FLAC_API const unsigned FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN = 4; /* bits */
143FLAC_API const unsigned FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN = 5; /* bits */
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000144
Josh Coalson6afed9f2002-10-16 22:29:47 +0000145FLAC_API const unsigned FLAC__SUBFRAME_ZERO_PAD_LEN = 1; /* bits */
146FLAC_API const unsigned FLAC__SUBFRAME_TYPE_LEN = 6; /* bits */
147FLAC_API const unsigned FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN = 1; /* bits */
Josh Coalson215af572001-03-27 01:15:58 +0000148
Josh Coalson6afed9f2002-10-16 22:29:47 +0000149FLAC_API const unsigned FLAC__SUBFRAME_TYPE_CONSTANT_BYTE_ALIGNED_MASK = 0x00;
150FLAC_API const unsigned FLAC__SUBFRAME_TYPE_VERBATIM_BYTE_ALIGNED_MASK = 0x02;
151FLAC_API const unsigned FLAC__SUBFRAME_TYPE_FIXED_BYTE_ALIGNED_MASK = 0x10;
152FLAC_API const unsigned FLAC__SUBFRAME_TYPE_LPC_BYTE_ALIGNED_MASK = 0x40;
Josh Coalson75d0a0b2001-01-24 00:42:16 +0000153
Josh Coalson6afed9f2002-10-16 22:29:47 +0000154FLAC_API const char * const FLAC__SubframeTypeString[] = {
Josh Coalson75d0a0b2001-01-24 00:42:16 +0000155 "CONSTANT",
156 "VERBATIM",
157 "FIXED",
158 "LPC"
159};
160
Josh Coalson6afed9f2002-10-16 22:29:47 +0000161FLAC_API const char * const FLAC__ChannelAssignmentString[] = {
Josh Coalson75d0a0b2001-01-24 00:42:16 +0000162 "INDEPENDENT",
163 "LEFT_SIDE",
164 "RIGHT_SIDE",
165 "MID_SIDE"
166};
167
Josh Coalson6afed9f2002-10-16 22:29:47 +0000168FLAC_API const char * const FLAC__FrameNumberTypeString[] = {
Josh Coalson96084632001-07-16 18:07:12 +0000169 "FRAME_NUMBER_TYPE_FRAME_NUMBER",
170 "FRAME_NUMBER_TYPE_SAMPLE_NUMBER"
171};
172
Josh Coalson6afed9f2002-10-16 22:29:47 +0000173FLAC_API const char * const FLAC__MetadataTypeString[] = {
Josh Coalson20135722001-02-23 21:05:53 +0000174 "STREAMINFO",
175 "PADDING",
Josh Coalson9b04be72001-06-14 18:57:53 +0000176 "APPLICATION",
Josh Coalson7e19b542002-04-25 05:53:09 +0000177 "SEEKTABLE",
Josh Coalsone4869382002-11-15 05:41:48 +0000178 "VORBIS_COMMENT",
Josh Coalsone343ab22006-09-23 19:21:19 +0000179 "CUESHEET",
180 "PICTURE"
181};
182
183FLAC_API const char * const FLAC__StreamMetadata_Picture_TypeString[] = {
184 "Other",
185 "32x32 pixels 'file icon' (PNG only)",
186 "Other file icon",
187 "Cover (front)",
188 "Cover (back)",
189 "Leaflet page",
190 "Media (e.g. label side of CD)",
191 "Lead artist/lead performer/soloist",
192 "Artist/performer",
193 "Conductor",
194 "Band/Orchestra",
195 "Composer",
196 "Lyricist/text writer",
197 "Recording Location",
198 "During recording",
199 "During performance",
200 "Movie/video screen capture",
201 "A bright coloured fish",
202 "Illustration",
203 "Band/artist logotype",
204 "Publisher/Studio logotype"
Josh Coalson75d0a0b2001-01-24 00:42:16 +0000205};
Josh Coalsoncc059bc2002-05-04 17:35:51 +0000206
Josh Coalson6afed9f2002-10-16 22:29:47 +0000207FLAC_API FLAC__bool FLAC__format_sample_rate_is_valid(unsigned sample_rate)
Josh Coalsoncc059bc2002-05-04 17:35:51 +0000208{
209 if(
210 sample_rate == 0 ||
211 sample_rate > FLAC__MAX_SAMPLE_RATE ||
212 (
Josh Coalson765ff502002-08-27 05:46:11 +0000213 sample_rate >= (1u << 16) &&
Josh Coalsoncc059bc2002-05-04 17:35:51 +0000214 !(sample_rate % 1000 == 0 || sample_rate % 10 == 0)
215 )
216 ) {
217 return false;
218 }
219 else
220 return true;
221}
Josh Coalson0d36cbd2002-07-15 05:24:56 +0000222
Josh Coalson6afed9f2002-10-16 22:29:47 +0000223FLAC_API FLAC__bool FLAC__format_seektable_is_legal(const FLAC__StreamMetadata_SeekTable *seek_table)
Josh Coalson0d36cbd2002-07-15 05:24:56 +0000224{
225 unsigned i;
226 FLAC__uint64 prev_sample_number = 0;
227 FLAC__bool got_prev = false;
228
229 FLAC__ASSERT(0 != seek_table);
230
231 for(i = 0; i < seek_table->num_points; i++) {
232 if(got_prev) {
Josh Coalson5a5de732002-08-01 06:37:11 +0000233 if(
234 seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER &&
235 seek_table->points[i].sample_number <= prev_sample_number
236 )
Josh Coalson0d36cbd2002-07-15 05:24:56 +0000237 return false;
238 }
239 prev_sample_number = seek_table->points[i].sample_number;
240 got_prev = true;
241 }
242
243 return true;
244}
Josh Coalson5a5de732002-08-01 06:37:11 +0000245
246/* used as the sort predicate for qsort() */
247static int seekpoint_compare_(const FLAC__StreamMetadata_SeekPoint *l, const FLAC__StreamMetadata_SeekPoint *r)
248{
249 /* we don't just 'return l->sample_number - r->sample_number' since the result (FLAC__int64) might overflow an 'int' */
250 if(l->sample_number == r->sample_number)
251 return 0;
252 else if(l->sample_number < r->sample_number)
253 return -1;
254 else
255 return 1;
256}
257
Josh Coalson6afed9f2002-10-16 22:29:47 +0000258FLAC_API unsigned FLAC__format_seektable_sort(FLAC__StreamMetadata_SeekTable *seek_table)
Josh Coalson5a5de732002-08-01 06:37:11 +0000259{
260 unsigned i, j;
261 FLAC__bool first;
262
Josh Coalsona0ac09a2002-08-16 05:40:16 +0000263 FLAC__ASSERT(0 != seek_table);
264
Josh Coalson5a5de732002-08-01 06:37:11 +0000265 /* sort the seekpoints */
266 qsort(seek_table->points, seek_table->num_points, sizeof(FLAC__StreamMetadata_SeekPoint), (int (*)(const void *, const void *))seekpoint_compare_);
267
268 /* uniquify the seekpoints */
269 first = true;
270 for(i = j = 0; i < seek_table->num_points; i++) {
271 if(seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER) {
272 if(!first) {
273 if(seek_table->points[i].sample_number == seek_table->points[j-1].sample_number)
274 continue;
275 }
276 }
277 first = false;
278 seek_table->points[j++] = seek_table->points[i];
279 }
280
Josh Coalson08a62822002-08-01 07:33:36 +0000281 for(i = j; i < seek_table->num_points; i++) {
282 seek_table->points[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
283 seek_table->points[i].stream_offset = 0;
284 seek_table->points[i].frame_samples = 0;
Josh Coalson5a5de732002-08-01 06:37:11 +0000285 }
286
287 return j;
288}
Josh Coalsoncda4c3c2002-08-17 15:21:29 +0000289
Josh Coalsonf2a8e062005-08-24 07:37:11 +0000290/*
291 * also disallows non-shortest-form encodings, c.f.
292 * http://www.unicode.org/versions/corrigendum1.html
293 * and a more clear explanation at the end of this section:
294 * http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
295 */
Josh Coalson2de11242004-12-30 03:41:19 +0000296static __inline unsigned utf8len_(const FLAC__byte *utf8)
297{
298 FLAC__ASSERT(0 != utf8);
Josh Coalsonf2a8e062005-08-24 07:37:11 +0000299 if ((utf8[0] & 0x80) == 0) {
Josh Coalson2de11242004-12-30 03:41:19 +0000300 return 1;
Josh Coalsonf2a8e062005-08-24 07:37:11 +0000301 }
302 else if ((utf8[0] & 0xE0) == 0xC0 && (utf8[1] & 0xC0) == 0x80) {
Josh Coalsonc6e53da2005-08-25 00:22:06 +0000303 if ((utf8[0] & 0xFE) == 0xC0) /* overlong sequence check */
Josh Coalsonf2a8e062005-08-24 07:37:11 +0000304 return 0;
Josh Coalson2de11242004-12-30 03:41:19 +0000305 return 2;
Josh Coalsonf2a8e062005-08-24 07:37:11 +0000306 }
307 else if ((utf8[0] & 0xF0) == 0xE0 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80) {
308 if (utf8[0] == 0xE0 && (utf8[1] & 0xE0) == 0x80) /* overlong sequence check */
309 return 0;
310 /* illegal surrogates check (U+D800...U+DFFF and U+FFFE...U+FFFF) */
311 if (utf8[0] == 0xED && (utf8[1] & 0xE0) == 0xA0) /* D800-DFFF */
312 return 0;
313 if (utf8[0] == 0xEF && utf8[1] == 0xBF && (utf8[2] & 0xFE) == 0xBE) /* FFFE-FFFF */
314 return 0;
Josh Coalson2de11242004-12-30 03:41:19 +0000315 return 3;
Josh Coalsonf2a8e062005-08-24 07:37:11 +0000316 }
317 else if ((utf8[0] & 0xF8) == 0xF0 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80) {
318 if (utf8[0] == 0xF0 && (utf8[1] & 0xF0) == 0x80) /* overlong sequence check */
319 return 0;
320 return 4;
321 }
322 else if ((utf8[0] & 0xFC) == 0xF8 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80 && (utf8[4] & 0xC0) == 0x80) {
323 if (utf8[0] == 0xF8 && (utf8[1] & 0xF8) == 0x80) /* overlong sequence check */
324 return 0;
325 return 5;
326 }
327 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) {
328 if (utf8[0] == 0xFC && (utf8[1] & 0xFC) == 0x80) /* overlong sequence check */
329 return 0;
330 return 6;
331 }
332 else {
Josh Coalson2de11242004-12-30 03:41:19 +0000333 return 0;
Josh Coalsonf2a8e062005-08-24 07:37:11 +0000334 }
Josh Coalson2de11242004-12-30 03:41:19 +0000335}
336
337FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_name_is_legal(const char *name)
338{
339 char c;
340 for(c = *name; c; c = *(++name))
341 if(c < 0x20 || c == 0x3d || c > 0x7d)
342 return false;
343 return true;
344}
345
346FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_value_is_legal(const FLAC__byte *value, unsigned length)
347{
348 if(length == (unsigned)(-1)) {
349 while(*value) {
350 unsigned n = utf8len_(value);
351 if(n == 0)
352 return false;
353 value += n;
354 }
355 }
356 else {
357 const FLAC__byte *end = value + length;
358 while(value < end) {
359 unsigned n = utf8len_(value);
360 if(n == 0)
361 return false;
362 value += n;
363 }
364 if(value != end)
365 return false;
366 }
367 return true;
368}
369
370FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_is_legal(const FLAC__byte *entry, unsigned length)
371{
372 const FLAC__byte *s, *end;
373
374 for(s = entry, end = s + length; s < end && *s != '='; s++) {
375 if(*s < 0x20 || *s > 0x7D)
376 return false;
377 }
378 if(s == end)
379 return false;
380
381 s++; /* skip '=' */
382
383 while(s < end) {
384 unsigned n = utf8len_(s);
385 if(n == 0)
386 return false;
387 s += n;
388 }
389 if(s != end)
390 return false;
391
392 return true;
393}
394
Josh Coalson8e9c4512002-11-14 05:00:24 +0000395FLAC_API FLAC__bool FLAC__format_cuesheet_is_legal(const FLAC__StreamMetadata_CueSheet *cue_sheet, FLAC__bool check_cd_da_subset, const char **violation)
396{
397 unsigned i, j;
398
399 if(check_cd_da_subset) {
400 if(cue_sheet->lead_in < 2 * 44100) {
401 if(violation) *violation = "CD-DA cue sheet must have a lead-in length of at least 2 seconds";
402 return false;
403 }
404 if(cue_sheet->lead_in % 588 != 0) {
405 if(violation) *violation = "CD-DA cue sheet lead-in length must be evenly divisible by 588 samples";
406 return false;
407 }
408 }
409
410 if(cue_sheet->num_tracks == 0) {
411 if(violation) *violation = "cue sheet must have at least one track (the lead-out)";
412 return false;
413 }
414
415 if(check_cd_da_subset && cue_sheet->tracks[cue_sheet->num_tracks-1].number != 170) {
416 if(violation) *violation = "CD-DA cue sheet must have a lead-out track number 170 (0xAA)";
417 return false;
418 }
419
420 for(i = 0; i < cue_sheet->num_tracks; i++) {
421 if(cue_sheet->tracks[i].number == 0) {
422 if(violation) *violation = "cue sheet may not have a track number 0";
423 return false;
424 }
425
426 if(check_cd_da_subset) {
427 if(!((cue_sheet->tracks[i].number >= 1 && cue_sheet->tracks[i].number <= 99) || cue_sheet->tracks[i].number == 170)) {
428 if(violation) *violation = "CD-DA cue sheet track number must be 1-99 or 170";
429 return false;
430 }
431 }
432
433 if(check_cd_da_subset && cue_sheet->tracks[i].offset % 588 != 0) {
Josh Coalsonf2a8e062005-08-24 07:37:11 +0000434 if(violation) {
Josh Coalsonfe1d3112005-08-24 00:14:23 +0000435 if(i == cue_sheet->num_tracks-1) /* the lead-out track... */
436 *violation = "CD-DA cue sheet lead-out offset must be evenly divisible by 588 samples";
437 else
438 *violation = "CD-DA cue sheet track offset must be evenly divisible by 588 samples";
Josh Coalsonf2a8e062005-08-24 07:37:11 +0000439 }
Josh Coalson8e9c4512002-11-14 05:00:24 +0000440 return false;
441 }
442
Josh Coalson3f86cc72002-11-21 06:41:46 +0000443 if(i < cue_sheet->num_tracks - 1) {
444 if(cue_sheet->tracks[i].num_indices == 0) {
445 if(violation) *violation = "cue sheet track must have at least one index point";
446 return false;
447 }
Josh Coalson8e9c4512002-11-14 05:00:24 +0000448
Josh Coalson3f86cc72002-11-21 06:41:46 +0000449 if(cue_sheet->tracks[i].indices[0].number > 1) {
450 if(violation) *violation = "cue sheet track's first index number must be 0 or 1";
451 return false;
452 }
Josh Coalson8e9c4512002-11-14 05:00:24 +0000453 }
454
455 for(j = 0; j < cue_sheet->tracks[i].num_indices; j++) {
456 if(check_cd_da_subset && cue_sheet->tracks[i].indices[j].offset % 588 != 0) {
457 if(violation) *violation = "CD-DA cue sheet track index offset must be evenly divisible by 588 samples";
458 return false;
459 }
460
461 if(j > 0) {
462 if(cue_sheet->tracks[i].indices[j].number != cue_sheet->tracks[i].indices[j-1].number + 1) {
463 if(violation) *violation = "cue sheet track index numbers must increase by 1";
464 return false;
465 }
466 }
467 }
468 }
469
470 return true;
471}
472
Josh Coalsone343ab22006-09-23 19:21:19 +0000473FLAC_API FLAC__bool FLAC__format_picture_is_legal(const FLAC__StreamMetadata_Picture *picture, const char **violation)
474{
475 char *p;
476 FLAC__byte *b;
477
478 for(p = picture->mime_type; *p; p++) {
479 if(*p < 0x20 || *p > 0x7e) {
480 if(violation) *violation = "MIME type string must contain only printable ASCII characters (0x20-0x7e)";
481 return false;
482 }
483 }
484
485 for(b = picture->description; *b; ) {
486 unsigned n = utf8len_(b);
487 if(n == 0) {
488 if(violation) *violation = "description string must be valid UTF-8";
489 return false;
490 }
491 b += n;
492 }
493
494 return true;
495}
496
Josh Coalson8e9c4512002-11-14 05:00:24 +0000497/*
498 * These routines are private to libFLAC
499 */
Josh Coalsoncda4c3c2002-08-17 15:21:29 +0000500unsigned FLAC__format_get_max_rice_partition_order(unsigned blocksize, unsigned predictor_order)
501{
502 return
503 FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(
504 FLAC__format_get_max_rice_partition_order_from_blocksize(blocksize),
505 blocksize,
506 predictor_order
507 );
508}
509
510unsigned FLAC__format_get_max_rice_partition_order_from_blocksize(unsigned blocksize)
511{
512 unsigned max_rice_partition_order = 0;
513 while(!(blocksize & 1)) {
514 max_rice_partition_order++;
515 blocksize >>= 1;
516 }
517 return min(FLAC__MAX_RICE_PARTITION_ORDER, max_rice_partition_order);
518}
519
520unsigned FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(unsigned limit, unsigned blocksize, unsigned predictor_order)
521{
522 unsigned max_rice_partition_order = limit;
523
524 while(max_rice_partition_order > 0 && (blocksize >> max_rice_partition_order) <= predictor_order)
525 max_rice_partition_order--;
526
Josh Coalsonf12edc62002-10-11 06:24:33 +0000527 FLAC__ASSERT(
528 (max_rice_partition_order == 0 && blocksize >= predictor_order) ||
529 (max_rice_partition_order > 0 && blocksize >> max_rice_partition_order > predictor_order)
530 );
Josh Coalsoncda4c3c2002-08-17 15:21:29 +0000531
532 return max_rice_partition_order;
533}
534
Josh Coalsona37ba462002-08-19 21:36:39 +0000535void FLAC__format_entropy_coding_method_partitioned_rice_contents_init(FLAC__EntropyCodingMethod_PartitionedRiceContents *object)
Josh Coalsoncda4c3c2002-08-17 15:21:29 +0000536{
537 FLAC__ASSERT(0 != object);
538
Josh Coalsoncda4c3c2002-08-17 15:21:29 +0000539 object->parameters = 0;
540 object->raw_bits = 0;
541 object->capacity_by_order = 0;
542}
543
Josh Coalsona37ba462002-08-19 21:36:39 +0000544void FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(FLAC__EntropyCodingMethod_PartitionedRiceContents *object)
Josh Coalsoncda4c3c2002-08-17 15:21:29 +0000545{
546 FLAC__ASSERT(0 != object);
547
548 if(0 != object->parameters)
549 free(object->parameters);
550 if(0 != object->raw_bits)
551 free(object->raw_bits);
Josh Coalsona37ba462002-08-19 21:36:39 +0000552 FLAC__format_entropy_coding_method_partitioned_rice_contents_init(object);
Josh Coalsoncda4c3c2002-08-17 15:21:29 +0000553}
554
Josh Coalsona37ba462002-08-19 21:36:39 +0000555FLAC__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 +0000556{
557 FLAC__ASSERT(0 != object);
558
559 FLAC__ASSERT(object->capacity_by_order > 0 || (0 == object->parameters && 0 == object->raw_bits));
560
561 if(object->capacity_by_order < max_partition_order) {
Josh Coalson5e3fcb22002-11-06 07:11:26 +0000562 if(0 == (object->parameters = (unsigned*)realloc(object->parameters, sizeof(unsigned)*(1 << max_partition_order))))
Josh Coalsoncda4c3c2002-08-17 15:21:29 +0000563 return false;
Josh Coalson5e3fcb22002-11-06 07:11:26 +0000564 if(0 == (object->raw_bits = (unsigned*)realloc(object->raw_bits, sizeof(unsigned)*(1 << max_partition_order))))
Josh Coalsoncda4c3c2002-08-17 15:21:29 +0000565 return false;
566 object->capacity_by_order = max_partition_order;
567 }
568
569 return true;
570}