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