1 ////////////////////////////////////////////////////////////////////////////
2 // **** WAVPACK **** //
3 // Hybrid Lossless Wavefile Compressor //
4 // Copyright (c) 1998 - 2019 David Bryant. //
5 // All Rights Reserved. //
6 // Distributed under the BSD Software License (see license.txt) //
7 ////////////////////////////////////////////////////////////////////////////
8
9 // caff.c
10
11 // This module is a helper to the WavPack command-line programs to support CAF files.
12
13 #include <string.h>
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <math.h>
17
18 #include "wavpack.h"
19 #include "utils.h"
20
21 #ifdef _WIN32
22 #define strdup(x) _strdup(x)
23 #endif
24
25
26 #define WAVPACK_NO_ERROR 0
27 #define WAVPACK_SOFT_ERROR 1
28 #define WAVPACK_HARD_ERROR 2
29
30 extern int debug_logging_mode;
31
32 typedef struct
33 {
34 char mFileType [4];
35 uint16_t mFileVersion;
36 uint16_t mFileFlags;
37 } CAFFileHeader;
38
39 #define CAFFileHeaderFormat "4SS"
40
41 #pragma pack(push,4)
42 typedef struct
43 {
44 char mChunkType [4];
45 int64_t mChunkSize;
46 } CAFChunkHeader;
47 #pragma pack(pop)
48
49 #define CAFChunkHeaderFormat "4D"
50
51 typedef struct
52 {
53 double mSampleRate;
54 char mFormatID [4];
55 uint32_t mFormatFlags;
56 uint32_t mBytesPerPacket;
57 uint32_t mFramesPerPacket;
58 uint32_t mChannelsPerFrame;
59 uint32_t mBitsPerChannel;
60 } CAFAudioFormat;
61
62 #define CAFAudioFormatFormat "D4LLLLL"
63 #define CAF_FORMAT_FLOAT 0x1
64 #define CAF_FORMAT_LITTLE_ENDIAN 0x2
65
66 typedef struct
67 {
68 uint32_t mChannelLayoutTag;
69 uint32_t mChannelBitmap;
70 uint32_t mNumberChannelDescriptions;
71 } CAFChannelLayout;
72
73 #define CAFChannelLayoutFormat "LLL"
74
75 enum {
76 kCAFChannelLayoutTag_UseChannelDescriptions = (0<<16) | 0, // use the array of AudioChannelDescriptions to define the mapping.
77 kCAFChannelLayoutTag_UseChannelBitmap = (1<<16) | 0, // use the bitmap to define the mapping.
78 };
79
80 typedef struct
81 {
82 uint32_t mChannelLabel;
83 uint32_t mChannelFlags;
84 float mCoordinates [3];
85 } CAFChannelDescription;
86
87 #define CAFChannelDescriptionFormat "LLLLL"
88
89 static const char TMH_full [] = { 1,2,3,13,9,10,5,6,12,14,15,16,17,9,4,18,7,8,19,20,21,0 };
90 static const char TMH_std [] = { 1,2,3,11,8,9,5,6,10,12,13,14,15,7,4,16,0 };
91
92 static struct {
93 uint32_t mChannelLayoutTag; // Core Audio layout, 100 - 146 in high word, num channels in low word
94 uint32_t mChannelBitmap; // Microsoft standard mask (for those channels that appear)
95 const char *mChannelReorder; // reorder string if layout is NOT in Microsoft standard order
96 const char *mChannelIdentities; // identities of any channels NOT in Microsoft standard
97 } layouts [] = {
98 { (100<<16) | 1, 0x004, NULL, NULL }, // FC
99 { (101<<16) | 2, 0x003, NULL, NULL }, // FL, FR
100 { (102<<16) | 2, 0x003, NULL, NULL }, // FL, FR (headphones)
101 { (103<<16) | 2, 0x000, NULL, "\46\47" }, // [Lt, Rt] (matrix encoded)
102 { (104<<16) | 2, 0x000, NULL, "\314\315" }, // [Mid, Side]
103 { (105<<16) | 2, 0x000, NULL, "\316\317" }, // [X, Y]
104 { (106<<16) | 2, 0x003, NULL, NULL }, // FL, FR (binaural)
105 { (107<<16) | 4, 0x000, NULL, "\310\311\312\313" }, // [W, X, Y, Z] (ambisonics)
106 { (108<<16) | 4, 0x033, NULL, NULL }, // FL, FR, BL, BR (quad)
107 { (109<<16) | 5, 0x037, "12453", NULL }, // FL, FR, BL, BR, FC (pentagonal)
108 { (110<<16) | 6, 0x137, "124536", NULL }, // FL, FR, BL, BR, FC, BC (hexagonal)
109 { (111<<16) | 8, 0x737, "12453678", NULL }, // FL, FR, BL, BR, FC, BC, SL, SR (octagonal)
110 { (112<<16) | 8, 0x2d033, NULL, NULL }, // FL, FR, BL, BR, TFL, TFR, TBL, TBR (cubic)
111 { (113<<16) | 3, 0x007, NULL, NULL }, // FL, FR, FC
112 { (114<<16) | 3, 0x007, "312", NULL }, // FC, FL, FR
113 { (115<<16) | 4, 0x107, NULL, NULL }, // FL, FR, FC, BC
114 { (116<<16) | 4, 0x107, "3124", NULL }, // FC, FL, FR, BC
115 { (117<<16) | 5, 0x037, NULL, NULL }, // FL, FR, FC, BL, BR
116 { (118<<16) | 5, 0x037, "12453", NULL }, // FL, FR, BL, BR, FC
117 { (119<<16) | 5, 0x037, "13245", NULL }, // FL, FC, FR, BL, BR
118 { (120<<16) | 5, 0x037, "31245", NULL }, // FC, FL, FR, BL, BR
119 { (121<<16) | 6, 0x03f, NULL, NULL }, // FL, FR, FC, LFE, BL, BR
120 { (122<<16) | 6, 0x03f, "125634", NULL }, // FL, FR, BL, BR, FC, LFE
121 { (123<<16) | 6, 0x03f, "132564", NULL }, // FL, FC, FR, BL, BR, LFE
122 { (124<<16) | 6, 0x03f, "312564", NULL }, // FC, FL, FR, BL, BR, LFE
123 { (125<<16) | 7, 0x13f, NULL, NULL }, // FL, FR, FC, LFE, BL, BR, BC
124 { (126<<16) | 8, 0x0ff, NULL, NULL }, // FL, FR, FC, LFE, BL, BR, FLC, FRC
125 { (127<<16) | 8, 0x0ff, "37812564", NULL }, // FC, FLC, FRC, FL, FR, BL, BR, LFE
126 { (128<<16) | 8, 0x03f, NULL, "\41\42" }, // FL, FR, FC, LFE, BL, BR, [Rls, Rrs]
127 { (129<<16) | 8, 0x0ff, "12563478", NULL }, // FL, FR, BL, BR, FC, LFE, FLC, FRC
128 { (130<<16) | 8, 0x03f, NULL, "\46\47" }, // FL, FR, FC, LFE, BL, BR, [Lt, Rt]
129 { (131<<16) | 3, 0x103, NULL, NULL }, // FL, FR, BC
130 { (132<<16) | 4, 0x033, NULL, NULL }, // FL, FR, BL, BR
131 { (133<<16) | 3, 0x00B, NULL, NULL }, // FL, FR, LFE
132 { (134<<16) | 4, 0x10B, NULL, NULL }, // FL, FR, LFE, BC
133 { (135<<16) | 5, 0x03B, NULL, NULL }, // FL, FR, LFE, BL, BR
134 { (136<<16) | 4, 0x00F, NULL, NULL }, // FL, FR, FC, LFE
135 { (137<<16) | 5, 0x10f, NULL, NULL }, // FL, FR, FC, LFE, BC
136 { (138<<16) | 5, 0x03b, "12453", NULL }, // FL, FR, BL, BR, LFE
137 { (139<<16) | 6, 0x137, "124536", NULL }, // FL, FR, BL, BR, FC, BC
138 { (140<<16) | 7, 0x037, "1245367", "\41\42" }, // FL, FR, BL, BR, FC, [Rls, Rrs]
139 { (141<<16) | 6, 0x137, "312456", NULL }, // FC, FL, FR, BL, BR, BC
140 { (142<<16) | 7, 0x13f, "3125674", NULL }, // FC, FL, FR, BL, BR, BC, LFE
141 { (143<<16) | 7, 0x037, "3124567", "\41\42" }, // FC, FL, FR, BL, BR, [Rls, Rrs]
142 { (144<<16) | 8, 0x137, "31245786", "\41\42" }, // FC, FL, FR, BL, BR, [Rls, Rrs], BC
143 { (145<<16) | 16, 0x773f, TMH_std, "\43\44\54\45" }, // FL, FR, FC, TFC, SL, SR, BL, BR, TFL, TFR, [Lw, Rw, Csd], BC, LFE, [LFE2]
144 { (146<<16) | 21, 0x77ff, TMH_full, "\43\44\54\45" }, // FL, FR, FC, TFC, SL, SR, BL, BR, TFL, TFR, [Lw, Rw, Csd], BC, LFE, [LFE2],
145 // FLC, FRC, [HI, VI, Haptic]
146 };
147
148 #define NUM_LAYOUTS (sizeof (layouts) / sizeof (layouts [0]))
149
ParseCaffHeaderConfig(FILE * infile,char * infilename,char * fourcc,WavpackContext * wpc,WavpackConfig * config)150 int ParseCaffHeaderConfig (FILE *infile, char *infilename, char *fourcc, WavpackContext *wpc, WavpackConfig *config)
151 {
152 uint32_t chan_chunk = 0, desc_chunk = 0, channel_layout = 0, bcount;
153 unsigned char *channel_identities = NULL;
154 unsigned char *channel_reorder = NULL;
155 int64_t total_samples = 0, infilesize;
156 CAFFileHeader caf_file_header;
157 CAFChunkHeader caf_chunk_header;
158 CAFAudioFormat caf_audio_format;
159 int i;
160
161 infilesize = DoGetFileSize (infile);
162 memcpy (&caf_file_header, fourcc, 4);
163
164 if ((!DoReadFile (infile, ((char *) &caf_file_header) + 4, sizeof (CAFFileHeader) - 4, &bcount) ||
165 bcount != sizeof (CAFFileHeader) - 4)) {
166 error_line ("%s is not a valid .CAF file!", infilename);
167 return WAVPACK_SOFT_ERROR;
168 }
169 else if (!(config->qmode & QMODE_NO_STORE_WRAPPER) &&
170 !WavpackAddWrapper (wpc, &caf_file_header, sizeof (CAFFileHeader))) {
171 error_line ("%s", WavpackGetErrorMessage (wpc));
172 return WAVPACK_SOFT_ERROR;
173 }
174
175 WavpackBigEndianToNative (&caf_file_header, CAFFileHeaderFormat);
176
177 if (caf_file_header.mFileVersion != 1) {
178 error_line ("%s: can't handle version %d .CAF files!", infilename, caf_file_header.mFileVersion);
179 return WAVPACK_SOFT_ERROR;
180 }
181
182 // loop through all elements of the RIFF wav header
183 // (until the data chuck) and copy them to the output file
184
185 while (1) {
186 if (!DoReadFile (infile, &caf_chunk_header, sizeof (CAFChunkHeader), &bcount) ||
187 bcount != sizeof (CAFChunkHeader)) {
188 error_line ("%s is not a valid .CAF file!", infilename);
189 return WAVPACK_SOFT_ERROR;
190 }
191 else if (!(config->qmode & QMODE_NO_STORE_WRAPPER) &&
192 !WavpackAddWrapper (wpc, &caf_chunk_header, sizeof (CAFChunkHeader))) {
193 error_line ("%s", WavpackGetErrorMessage (wpc));
194 return WAVPACK_SOFT_ERROR;
195 }
196
197 WavpackBigEndianToNative (&caf_chunk_header, CAFChunkHeaderFormat);
198
199 // if it's the format chunk, we want to get some info out of there and
200 // make sure it's a .caf file we can handle
201
202 if (!strncmp (caf_chunk_header.mChunkType, "desc", 4)) {
203 int supported = TRUE;
204
205 if (caf_chunk_header.mChunkSize != sizeof (CAFAudioFormat) ||
206 !DoReadFile (infile, &caf_audio_format, (uint32_t) caf_chunk_header.mChunkSize, &bcount) ||
207 bcount != caf_chunk_header.mChunkSize) {
208 error_line ("%s is not a valid .CAF file!", infilename);
209 return WAVPACK_SOFT_ERROR;
210 }
211 else if (!(config->qmode & QMODE_NO_STORE_WRAPPER) &&
212 !WavpackAddWrapper (wpc, &caf_audio_format, (uint32_t) caf_chunk_header.mChunkSize)) {
213 error_line ("%s", WavpackGetErrorMessage (wpc));
214 return WAVPACK_SOFT_ERROR;
215 }
216
217 WavpackBigEndianToNative (&caf_audio_format, CAFAudioFormatFormat);
218 desc_chunk = 1;
219
220 if (debug_logging_mode) {
221 char formatstr [5];
222
223 memcpy (formatstr, caf_audio_format.mFormatID, 4);
224 formatstr [4] = 0;
225 error_line ("format = %s, flags = %x, sampling rate = %g",
226 formatstr, caf_audio_format.mFormatFlags, caf_audio_format.mSampleRate);
227 error_line ("packet = %d bytes and %d frames",
228 caf_audio_format.mBytesPerPacket, caf_audio_format.mFramesPerPacket);
229 error_line ("channels per frame = %d, bits per channel = %d",
230 caf_audio_format.mChannelsPerFrame, caf_audio_format.mBitsPerChannel);
231 }
232
233 if (strncmp (caf_audio_format.mFormatID, "lpcm", 4) || (caf_audio_format.mFormatFlags & ~3))
234 supported = FALSE;
235 else if (caf_audio_format.mSampleRate < 1.0 || caf_audio_format.mSampleRate > 16777215.0 ||
236 caf_audio_format.mSampleRate != floor (caf_audio_format.mSampleRate))
237 supported = FALSE;
238 else if (!caf_audio_format.mChannelsPerFrame || caf_audio_format.mChannelsPerFrame > 256)
239 supported = FALSE;
240 else if (caf_audio_format.mBitsPerChannel < 1 || caf_audio_format.mBitsPerChannel > 32 ||
241 ((caf_audio_format.mFormatFlags & CAF_FORMAT_FLOAT) && caf_audio_format.mBitsPerChannel != 32))
242 supported = FALSE;
243 else if (caf_audio_format.mFramesPerPacket != 1 ||
244 caf_audio_format.mBytesPerPacket / caf_audio_format.mChannelsPerFrame < (caf_audio_format.mBitsPerChannel + 7) / 8 ||
245 caf_audio_format.mBytesPerPacket / caf_audio_format.mChannelsPerFrame > 4 ||
246 caf_audio_format.mBytesPerPacket % caf_audio_format.mChannelsPerFrame)
247 supported = FALSE;
248
249 if (!supported) {
250 error_line ("%s is an unsupported .CAF format!", infilename);
251 return WAVPACK_SOFT_ERROR;
252 }
253
254 config->bytes_per_sample = caf_audio_format.mBytesPerPacket / caf_audio_format.mChannelsPerFrame;
255 config->float_norm_exp = (caf_audio_format.mFormatFlags & CAF_FORMAT_FLOAT) ? 127 : 0;
256 config->bits_per_sample = caf_audio_format.mBitsPerChannel;
257 config->num_channels = caf_audio_format.mChannelsPerFrame;
258 config->sample_rate = (int) caf_audio_format.mSampleRate;
259
260 if (!(caf_audio_format.mFormatFlags & CAF_FORMAT_LITTLE_ENDIAN) && config->bytes_per_sample > 1)
261 config->qmode |= QMODE_BIG_ENDIAN;
262
263 if (config->bytes_per_sample == 1)
264 config->qmode |= QMODE_SIGNED_BYTES;
265
266 if (debug_logging_mode) {
267 if (config->float_norm_exp == 127)
268 error_line ("data format: 32-bit %s-endian floating point", (config->qmode & QMODE_BIG_ENDIAN) ? "big" : "little");
269 else
270 error_line ("data format: %d-bit %s-endian integers stored in %d byte(s)",
271 config->bits_per_sample, (config->qmode & QMODE_BIG_ENDIAN) ? "big" : "little", config->bytes_per_sample);
272 }
273 }
274 else if (!strncmp (caf_chunk_header.mChunkType, "chan", 4)) {
275 CAFChannelLayout *caf_channel_layout;
276
277 if (caf_chunk_header.mChunkSize < 0 || caf_chunk_header.mChunkSize > 1024 ||
278 caf_chunk_header.mChunkSize < sizeof (CAFChannelLayout)) {
279 error_line ("this .CAF file has an invalid 'chan' chunk!");
280 return WAVPACK_SOFT_ERROR;
281 }
282
283 if (debug_logging_mode)
284 error_line ("'chan' chunk is %d bytes", (int) caf_chunk_header.mChunkSize);
285
286 caf_channel_layout = malloc ((size_t) caf_chunk_header.mChunkSize);
287
288 if (!DoReadFile (infile, caf_channel_layout, (uint32_t) caf_chunk_header.mChunkSize, &bcount) ||
289 bcount != caf_chunk_header.mChunkSize) {
290 error_line ("%s is not a valid .CAF file!", infilename);
291 free (caf_channel_layout);
292 return WAVPACK_SOFT_ERROR;
293 }
294 else if (!(config->qmode & QMODE_NO_STORE_WRAPPER) &&
295 !WavpackAddWrapper (wpc, caf_channel_layout, (uint32_t) caf_chunk_header.mChunkSize)) {
296 error_line ("%s", WavpackGetErrorMessage (wpc));
297 free (caf_channel_layout);
298 return WAVPACK_SOFT_ERROR;
299 }
300
301 WavpackBigEndianToNative (caf_channel_layout, CAFChannelLayoutFormat);
302 chan_chunk = 1;
303
304 if (config->channel_mask || (config->qmode & QMODE_CHANS_UNASSIGNED)) {
305 error_line ("this CAF file already has channel order information!");
306 free (caf_channel_layout);
307 return WAVPACK_SOFT_ERROR;
308 }
309
310 switch (caf_channel_layout->mChannelLayoutTag) {
311 case kCAFChannelLayoutTag_UseChannelDescriptions:
312 {
313 CAFChannelDescription *descriptions = (CAFChannelDescription *) (caf_channel_layout + 1);
314 int num_descriptions = caf_channel_layout->mNumberChannelDescriptions;
315 int label, cindex = 0, idents = 0;
316
317 if (caf_chunk_header.mChunkSize != sizeof (CAFChannelLayout) + sizeof (CAFChannelDescription) * num_descriptions ||
318 num_descriptions != config->num_channels) {
319 error_line ("channel descriptions in 'chan' chunk are the wrong size!");
320 free (caf_channel_layout);
321 return WAVPACK_SOFT_ERROR;
322 }
323
324 if (num_descriptions >= 256) {
325 error_line ("%d channel descriptions is more than we can handle...ignoring!");
326 break;
327 }
328
329 // we allocate (and initialize to invalid values) a channel reorder array
330 // (even though we might not end up doing any reordering) and a string for
331 // any non-Microsoft channels we encounter
332
333 channel_reorder = malloc (num_descriptions);
334 memset (channel_reorder, -1, num_descriptions);
335 channel_identities = malloc (num_descriptions+1);
336
337 // convert the descriptions array to our native endian so it's easy to access
338
339 for (i = 0; i < num_descriptions; ++i) {
340 WavpackBigEndianToNative (descriptions + i, CAFChannelDescriptionFormat);
341
342 if (debug_logging_mode)
343 error_line ("chan %d --> %d", i + 1, descriptions [i].mChannelLabel);
344 }
345
346 // first, we go though and find any MS channels present, and move those to the beginning
347
348 for (label = 1; label <= 18; ++label)
349 for (i = 0; i < num_descriptions; ++i)
350 if (descriptions [i].mChannelLabel == label) {
351 config->channel_mask |= 1 << (label - 1);
352 channel_reorder [i] = cindex++;
353 break;
354 }
355
356 // next, we go though the channels again assigning any we haven't done
357
358 for (i = 0; i < num_descriptions; ++i)
359 if (channel_reorder [i] == (unsigned char) -1) {
360 uint32_t clabel = descriptions [i].mChannelLabel;
361
362 if (clabel == 0 || clabel == 0xffffffff || clabel == 100)
363 channel_identities [idents++] = 0xff;
364 else if ((clabel >= 33 && clabel <= 44) || (clabel >= 200 && clabel <= 207) || (clabel >= 301 && clabel <= 305))
365 channel_identities [idents++] = clabel >= 301 ? clabel - 80 : clabel;
366 else {
367 error_line ("warning: unknown channel descriptions label: %d", clabel);
368 channel_identities [idents++] = 0xff;
369 }
370
371 channel_reorder [i] = cindex++;
372 }
373
374 // then, go through the reordering array and see if we really have to reorder
375
376 for (i = 0; i < num_descriptions; ++i)
377 if (channel_reorder [i] != i)
378 break;
379
380 if (i == num_descriptions) {
381 free (channel_reorder); // no reordering required, so don't
382 channel_reorder = NULL;
383 }
384 else {
385 config->qmode |= QMODE_REORDERED_CHANS; // reordering required, put channel count into layout
386 channel_layout = num_descriptions;
387 }
388
389 if (!idents) { // if no non-MS channels, free the identities string
390 free (channel_identities);
391 channel_identities = NULL;
392 }
393 else
394 channel_identities [idents] = 0; // otherwise NULL terminate it
395
396 if (debug_logging_mode) {
397 error_line ("layout_tag = 0x%08x, so generated bitmap of 0x%08x from %d descriptions, %d non-MS",
398 caf_channel_layout->mChannelLayoutTag, config->channel_mask,
399 caf_channel_layout->mNumberChannelDescriptions, idents);
400
401 // if debugging, display the reordering as a string (but only little ones)
402
403 if (channel_reorder && num_descriptions <= 8) {
404 char reorder_string [] = "12345678";
405
406 for (i = 0; i < num_descriptions; ++i)
407 reorder_string [i] = channel_reorder [i] + '1';
408
409 reorder_string [i] = 0;
410 error_line ("reordering string = \"%s\"\n", reorder_string);
411 }
412 }
413 }
414
415 break;
416
417 case kCAFChannelLayoutTag_UseChannelBitmap:
418 config->channel_mask = caf_channel_layout->mChannelBitmap;
419
420 if (debug_logging_mode)
421 error_line ("layout_tag = 0x%08x, so using supplied bitmap of 0x%08x",
422 caf_channel_layout->mChannelLayoutTag, caf_channel_layout->mChannelBitmap);
423
424 break;
425
426 default:
427 for (i = 0; i < NUM_LAYOUTS; ++i)
428 if (caf_channel_layout->mChannelLayoutTag == layouts [i].mChannelLayoutTag) {
429 config->channel_mask = layouts [i].mChannelBitmap;
430 channel_layout = layouts [i].mChannelLayoutTag;
431
432 if (layouts [i].mChannelReorder) {
433 channel_reorder = (unsigned char *) strdup (layouts [i].mChannelReorder);
434 config->qmode |= QMODE_REORDERED_CHANS;
435 }
436
437 if (layouts [i].mChannelIdentities)
438 channel_identities = (unsigned char *) strdup (layouts [i].mChannelIdentities);
439
440 if (debug_logging_mode)
441 error_line ("layout_tag 0x%08x found in table, bitmap = 0x%08x, reorder = %s, identities = %s",
442 channel_layout, config->channel_mask, channel_reorder ? "yes" : "no", channel_identities ? "yes" : "no");
443
444 break;
445 }
446
447 if (i == NUM_LAYOUTS && debug_logging_mode)
448 error_line ("layout_tag 0x%08x not found in table...all channels unassigned",
449 caf_channel_layout->mChannelLayoutTag);
450
451 break;
452 }
453
454 free (caf_channel_layout);
455 }
456 else if (!strncmp (caf_chunk_header.mChunkType, "data", 4)) { // on the data chunk, get size and exit loop
457 uint32_t mEditCount;
458
459 if (!desc_chunk || !DoReadFile (infile, &mEditCount, sizeof (mEditCount), &bcount) ||
460 bcount != sizeof (mEditCount)) {
461 error_line ("%s is not a valid .CAF file!", infilename);
462 return WAVPACK_SOFT_ERROR;
463 }
464 else if (!(config->qmode & QMODE_NO_STORE_WRAPPER) &&
465 !WavpackAddWrapper (wpc, &mEditCount, sizeof (mEditCount))) {
466 error_line ("%s", WavpackGetErrorMessage (wpc));
467 return WAVPACK_SOFT_ERROR;
468 }
469
470 if ((config->qmode & QMODE_IGNORE_LENGTH) || caf_chunk_header.mChunkSize == -1) {
471 config->qmode |= QMODE_IGNORE_LENGTH;
472
473 if (infilesize && DoGetFilePosition (infile) != -1) {
474 total_samples = (infilesize - DoGetFilePosition (infile)) / caf_audio_format.mBytesPerPacket;
475
476 if ((infilesize - DoGetFilePosition (infile)) % caf_audio_format.mBytesPerPacket)
477 error_line ("warning: audio length does not divide evenly, %d bytes will be discarded!",
478 (int)((infilesize - DoGetFilePosition (infile)) % caf_audio_format.mBytesPerPacket));
479 }
480 else
481 total_samples = -1;
482 }
483 else {
484 if (infilesize && infilesize - caf_chunk_header.mChunkSize > 16777216) {
485 error_line (".CAF file %s has over 16 MB of extra CAFF data, probably is corrupt!", infilename);
486 return WAVPACK_SOFT_ERROR;
487 }
488
489 if ((caf_chunk_header.mChunkSize - 4) % caf_audio_format.mBytesPerPacket) {
490 error_line (".CAF file %s has an invalid data chunk size, probably is corrupt!", infilename);
491 return WAVPACK_SOFT_ERROR;
492 }
493
494 total_samples = (caf_chunk_header.mChunkSize - 4) / caf_audio_format.mBytesPerPacket;
495
496 if (!total_samples) {
497 error_line ("this .CAF file has no audio samples, probably is corrupt!");
498 return WAVPACK_SOFT_ERROR;
499 }
500
501 if (total_samples > MAX_WAVPACK_SAMPLES) {
502 error_line ("%s has too many samples for WavPack!", infilename);
503 return WAVPACK_SOFT_ERROR;
504 }
505 }
506
507 break;
508 }
509 else { // just copy unknown chunks to output file
510
511 uint32_t bytes_to_copy = (uint32_t) caf_chunk_header.mChunkSize;
512 char *buff;
513
514 if (caf_chunk_header.mChunkSize < 0 || caf_chunk_header.mChunkSize > 1048576) {
515 error_line ("%s is not a valid .CAF file!", infilename);
516 return WAVPACK_SOFT_ERROR;
517 }
518
519 buff = malloc (bytes_to_copy);
520
521 if (debug_logging_mode)
522 error_line ("extra unknown chunk \"%c%c%c%c\" of %d bytes",
523 caf_chunk_header.mChunkType [0], caf_chunk_header.mChunkType [1], caf_chunk_header.mChunkType [2],
524 caf_chunk_header.mChunkType [3], caf_chunk_header.mChunkSize);
525
526 if (!DoReadFile (infile, buff, bytes_to_copy, &bcount) ||
527 bcount != bytes_to_copy ||
528 (!(config->qmode & QMODE_NO_STORE_WRAPPER) &&
529 !WavpackAddWrapper (wpc, buff, bytes_to_copy))) {
530 error_line ("%s", WavpackGetErrorMessage (wpc));
531 free (buff);
532 return WAVPACK_SOFT_ERROR;
533 }
534
535 free (buff);
536 }
537 }
538
539 if (!chan_chunk && !config->channel_mask && config->num_channels <= 2 && !(config->qmode & QMODE_CHANS_UNASSIGNED))
540 config->channel_mask = 0x5 - config->num_channels;
541
542 if (!WavpackSetConfiguration64 (wpc, config, total_samples, channel_identities)) {
543 error_line ("%s", WavpackGetErrorMessage (wpc));
544 return WAVPACK_SOFT_ERROR;
545 }
546
547 if (channel_identities)
548 free (channel_identities);
549
550 if (channel_layout || channel_reorder) {
551 if (!WavpackSetChannelLayout (wpc, channel_layout, channel_reorder)) {
552 error_line ("problem with setting channel layout (should not happen)");
553 return WAVPACK_SOFT_ERROR;
554 }
555
556 if (channel_reorder)
557 free (channel_reorder);
558 }
559
560 return WAVPACK_NO_ERROR;
561 }
562