1 /*
2      File: AudioFileObject.cpp
3  Abstract: AudioFileObject.h
4   Version: 1.1
5 
6  Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple
7  Inc. ("Apple") in consideration of your agreement to the following
8  terms, and your use, installation, modification or redistribution of
9  this Apple software constitutes acceptance of these terms.  If you do
10  not agree with these terms, please do not use, install, modify or
11  redistribute this Apple software.
12 
13  In consideration of your agreement to abide by the following terms, and
14  subject to these terms, Apple grants you a personal, non-exclusive
15  license, under Apple's copyrights in this original Apple software (the
16  "Apple Software"), to use, reproduce, modify and redistribute the Apple
17  Software, with or without modifications, in source and/or binary forms;
18  provided that if you redistribute the Apple Software in its entirety and
19  without modifications, you must retain this notice and the following
20  text and disclaimers in all such redistributions of the Apple Software.
21  Neither the name, trademarks, service marks or logos of Apple Inc. may
22  be used to endorse or promote products derived from the Apple Software
23  without specific prior written permission from Apple.  Except as
24  expressly stated in this notice, no other rights or licenses, express or
25  implied, are granted by Apple herein, including but not limited to any
26  patent rights that may be infringed by your derivative works or by other
27  works in which the Apple Software may be incorporated.
28 
29  The Apple Software is provided by Apple on an "AS IS" basis.  APPLE
30  MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
31  THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
32  FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
33  OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
34 
35  IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
36  OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
37  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
38  INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
39  MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
40  AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
41  STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
42  POSSIBILITY OF SUCH DAMAGE.
43 
44  Copyright (C) 2014 Apple Inc. All Rights Reserved.
45 
46 */
47 #include "AudioFileObject.h"
48 #include "CADebugMacros.h"
49 #include <algorithm>
50 #include <sys/stat.h>
51 
52 #define kAudioFileNoCacheMask		0x20
53 
54 const SInt64 kScanToEnd = 0x7fffFFFFffffFFFFLL;
55 
56 //////////////////////////////////////////////////////////////////////////////////////////////////////////
57 
~AudioFileObject()58 AudioFileObject::~AudioFileObject()
59 {
60 	delete mDataSource;
61 	DeletePacketTable();
62 	SetURL(NULL);
63 }
64 
65 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
66 
DoCreate(CFURLRef inFileRef,const AudioStreamBasicDescription * inFormat,UInt32 inFlags)67 OSStatus AudioFileObject::DoCreate(
68 									CFURLRef							inFileRef,
69 									const AudioStreamBasicDescription	*inFormat,
70 									UInt32								inFlags)
71 {
72 	// common prologue
73 	if (!IsDataFormatValid(inFormat))
74 		return kAudioFileUnsupportedDataFormatError;
75 
76 	if (!IsDataFormatSupported(inFormat))
77 		return kAudioFileUnsupportedDataFormatError;
78 
79 	SetPermissions(kAudioFileReadWritePermission);
80 
81 	SetAlignDataWithFillerChunks(!(inFlags & 2 /* kAudioFileFlags_DontPageAlignAudioData */ ));
82 
83 	// call virtual method for particular format.
84 	return Create(inFileRef, inFormat);
85 }
86 
87 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
88 
Create(CFURLRef inFileRef,const AudioStreamBasicDescription * inFormat)89 OSStatus AudioFileObject::Create(
90 									CFURLRef							inFileRef,
91 									const AudioStreamBasicDescription	*inFormat)
92 {
93 	int fileD;
94 	OSStatus err = CreateDataFile (inFileRef, fileD);
95     FailIf (err != noErr, Bail, "CreateDataFile failed");
96 
97 	SetURL (inFileRef);
98 
99 	err = OpenFile(kAudioFileReadWritePermission, fileD);
100     FailIf (err != noErr, Bail, "OpenFile failed");
101 
102 	err = SetDataFormat(inFormat);
103     FailIf (err != noErr, Bail, "SetDataFormat failed");
104 
105     mIsInitialized = false;
106 
107 Bail:
108 	return err;
109 }
110 
111 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
112 
DoOpen(CFURLRef inFileRef,SInt8 inPermissions,int inFD)113 OSStatus AudioFileObject::DoOpen(
114 									CFURLRef		inFileRef,
115 									SInt8  			inPermissions,
116 									int				inFD)
117 {
118 	OSStatus err = noErr;
119 	SetPermissions(inPermissions);
120 
121 	err = Open(inFileRef, inPermissions, inFD);
122     FailIf (err != noErr, Bail, "Open failed");
123 
124 	err = ValidateFormatAndData();
125     FailIf (err != noErr, Bail, "ValidateFormatAndData failed");
126 
127 Bail:
128 	return err;
129 }
130 
131 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
132 
Open(CFURLRef inFileRef,SInt8 inPermissions,int inFD)133 OSStatus AudioFileObject::Open(
134 									CFURLRef		inFileRef,
135 									SInt8  			inPermissions,
136 									int				inFD)
137 {
138 	if (!(inPermissions & kAudioFileReadPermission))
139 		return kAudioFilePermissionsError; // file must have read permissions
140 
141 	SetURL(inFileRef);
142 
143 	OSStatus err = OpenFile(inPermissions, inFD);
144     FailIf (err != noErr, Bail, "OpenFile failed");
145 
146 	err = OpenFromDataSource();
147     FailIf (err != noErr, Bail, "OpenFromDataSource failed");
148 
149 Bail:
150 	return err;
151 }
152 
153 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
154 
ValidateFormatAndData()155 OSStatus AudioFileObject::ValidateFormatAndData()
156 {
157 
158 
159 	AudioStreamBasicDescription asbd = GetDataFormat();
160 
161 	if (!IsDataFormatValid(&asbd))
162 		return kAudioFileInvalidFileError;
163 
164 	if (asbd.mFormatID == kAudioFormatLinearPCM)
165 	{
166 		SInt64 maxPackets = GetNumBytes() / asbd.mBytesPerPacket;
167 		if (GetNumPackets() > maxPackets)
168 			return kAudioFileInvalidFileError;
169 	}
170 	return noErr;
171 }
172 
173 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
174 
DoOpenWithCallbacks(void * inRefCon,AudioFile_ReadProc inReadFunc,AudioFile_WriteProc inWriteFunc,AudioFile_GetSizeProc inGetSizeFunc,AudioFile_SetSizeProc inSetSizeFunc)175 OSStatus AudioFileObject::DoOpenWithCallbacks(
176 				void *								inRefCon,
177 				AudioFile_ReadProc					inReadFunc,
178 				AudioFile_WriteProc					inWriteFunc,
179 				AudioFile_GetSizeProc				inGetSizeFunc,
180 				AudioFile_SetSizeProc				inSetSizeFunc)
181 {
182 	SInt8	perms = (inSetSizeFunc || inWriteFunc) ? kAudioFileReadWritePermission : kAudioFileReadPermission;
183 	SetPermissions(perms);
184 
185 	DataSource* dataSource = new Seekable_DataSource(inRefCon, inReadFunc, inWriteFunc, inGetSizeFunc, inSetSizeFunc);
186 	SetDataSource(dataSource);
187 	return OpenFromDataSource();
188 }
189 
190 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
191 
OpenFromDataSource(void)192 OSStatus AudioFileObject::OpenFromDataSource(void)
193 {
194 	return noErr;
195 }
196 
197 
198 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
199 
DoInitializeWithCallbacks(void * inRefCon,AudioFile_ReadProc inReadFunc,AudioFile_WriteProc inWriteFunc,AudioFile_GetSizeProc inGetSizeFunc,AudioFile_SetSizeProc inSetSizeFunc,UInt32 inFileType,const AudioStreamBasicDescription * inFormat,UInt32 inFlags)200 OSStatus AudioFileObject::DoInitializeWithCallbacks(
201 				void *								inRefCon,
202 				AudioFile_ReadProc					inReadFunc,
203 				AudioFile_WriteProc					inWriteFunc,
204 				AudioFile_GetSizeProc				inGetSizeFunc,
205 				AudioFile_SetSizeProc				inSetSizeFunc,
206                 UInt32								inFileType,
207 				const AudioStreamBasicDescription	*inFormat,
208 				UInt32								inFlags)
209 {
210 	DataSource* dataSource = new Seekable_DataSource(inRefCon, inReadFunc, inWriteFunc, inGetSizeFunc, inSetSizeFunc);
211 	if (!dataSource->CanWrite()) return -54/*permErr*/;
212 	dataSource->SetSize(0);
213 	SetDataSource(dataSource);
214 	SetPermissions(kAudioFileReadWritePermission);
215 
216 	SetAlignDataWithFillerChunks(!(inFlags & 2 /* kAudioFileFlags_DontPageAlignAudioData */ ));
217 
218 	OSStatus err = SetDataFormat(inFormat);
219 	if (err) return err;
220 
221 	return InitializeDataSource(inFormat, inFlags);
222 }
223 
224 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
225 
DoInitialize(CFURLRef inFileRef,const AudioStreamBasicDescription * inFormat,UInt32 inFlags)226 OSStatus AudioFileObject::DoInitialize(
227 									CFURLRef							inFileRef,
228 									const AudioStreamBasicDescription	*inFormat,
229 									UInt32			inFlags)
230 {
231 	SetURL (inFileRef);
232 	SetPermissions(kAudioFileReadWritePermission);
233 
234 	SetAlignDataWithFillerChunks(!(inFlags & 2 /* kAudioFileFlags_DontPageAlignAudioData */ ));
235 
236 	return Initialize(inFileRef, inFormat, inFlags);
237 }
238 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
239 
Initialize(CFURLRef inFileRef,const AudioStreamBasicDescription * inFormat,UInt32 inFlags)240 OSStatus AudioFileObject::Initialize(
241 									CFURLRef							inFileRef,
242 									const AudioStreamBasicDescription	*inFormat,
243 									UInt32								inFlags)
244 {
245 	OSStatus err = noErr;
246 
247 	UInt8 fPath[FILENAME_MAX];
248 	if (!CFURLGetFileSystemRepresentation (inFileRef, true, fPath, FILENAME_MAX))
249 		return kAudio_FileNotFoundError;
250 
251 #if TARGET_OS_WIN32
252 	int filePerms = 0;
253 	int flags = O_TRUNC | O_RDWR | O_BINARY;
254 #else
255 	mode_t filePerms = 0;
256 	int flags = O_TRUNC | O_RDWR;
257 #endif
258 
259 	int fileD = open((const char*)fPath, flags, filePerms);
260 	if (fileD < 0)
261 		return AudioFileTranslateErrno(errno);
262 
263 	err = OpenFile(kAudioFileReadWritePermission, fileD);
264     FailIf (err != noErr, Bail, "OpenFile failed");
265 
266 		// don't need to do this as open has an option to truncate the file
267 //	GetDataSource()->SetSize(0);
268 
269 	err = SetDataFormat(inFormat);
270     FailIf (err != noErr, Bail, "SetDataFormat failed");
271 
272 	InitializeDataSource(inFormat, inFlags);
273 
274 Bail:
275 	return err;
276 }
277 
278 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
279 
InitializeDataSource(const AudioStreamBasicDescription * inFormat,UInt32)280 OSStatus AudioFileObject::InitializeDataSource(const AudioStreamBasicDescription	*inFormat, UInt32 /*inFlags*/)
281 {
282 	return noErr;
283 }
284 
285 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
286 
DoClose()287 OSStatus AudioFileObject::DoClose()
288 {
289 	OSStatus err = UpdateSizeIfNeeded();
290 	if (err) return err;
291 
292 	return Close();
293 }
294 
295 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
296 
Close()297 OSStatus AudioFileObject::Close()
298 {
299     try {
300 		delete mDataSource;
301 		mDataSource = 0;
302 	} catch (OSStatus err) {
303 		return err;
304 	} catch (...) {
305 		return kAudioFileUnspecifiedError;
306 	}
307 	return noErr;
308 }
309 
310 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
311 
312 
Optimize()313 OSStatus AudioFileObject::Optimize()
314 {
315 	// default is that nothing needs to be done. This happens to be true for Raw, SD2 and NeXT/Sun types.
316 	SetIsOptimized(true);
317 	return noErr;
318 }
319 
320 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
321 
322 
DoOptimize()323 OSStatus AudioFileObject::DoOptimize()
324 {
325 	if (!CanWrite()) return kAudioFilePermissionsError;
326 
327 	OSStatus err = UpdateSizeIfNeeded();
328 	if (err) return err;
329 
330 	if (IsOptimized()) return noErr;
331 
332 	err = Optimize();
333 	return err;
334 }
335 
336 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
337 
UpdateNumBytes(SInt64 inNumBytes)338 OSStatus AudioFileObject::UpdateNumBytes(SInt64 inNumBytes)
339 {
340     OSStatus err = noErr;
341 	if (inNumBytes != GetNumBytes()) {
342 		SetNumBytes(inNumBytes);
343 
344         // #warning " this will not work for vbr formats"
345 		SetNumPackets(GetNumBytes() / mDataFormat.mBytesPerPacket);
346 		SizeChanged();
347 	}
348 	return err;
349 }
350 
351 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
352 
UpdateNumPackets(SInt64 inNumPackets)353 OSStatus AudioFileObject::UpdateNumPackets(SInt64 inNumPackets)
354 {
355     OSStatus err = noErr;
356 	if (inNumPackets != GetNumPackets()) {
357 		// sync current state.
358 		SetNeedsSizeUpdate(true);
359 		UpdateSizeIfNeeded();
360 		SetNumPackets(inNumPackets);
361 
362         // #warning " this will not work for vbr formats"
363 		SetNumBytes(GetNumPackets() * mDataFormat.mBytesPerFrame);
364 		SizeChanged();
365 	}
366 	return err;
367 }
368 
369 
370 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
371 
PacketToFrame(SInt64 inPacket,SInt64 & outFirstFrameInPacket)372 OSStatus AudioFileObject::PacketToFrame(SInt64 inPacket, SInt64& outFirstFrameInPacket)
373 {
374 	if (mDataFormat.mFramesPerPacket == 0)
375 	{
376 		OSStatus err = ScanForPackets(inPacket+1); // the packet count must be one greater than the packet index
377 		if (err) return err;
378 
379 		SInt64 packetTableSize = GetPacketTableSize();
380 
381 		if (mPacketTable && inPacket >= packetTableSize)
382 			return kAudioFileEndOfFileError;
383 
384 		CompressedPacketTable* packetTable = GetPacketTable();
385 		if (!packetTable)
386 			return kAudioFileInvalidPacketOffsetError;
387 
388 		if (inPacket < 0 || inPacket >= packetTableSize)
389 			return kAudioFileInvalidPacketOffsetError;
390 
391 		outFirstFrameInPacket = (*packetTable)[(size_t)inPacket].mFrameOffset;
392 	}
393 	else
394 	{
395 		outFirstFrameInPacket = inPacket * mDataFormat.mFramesPerPacket;
396 	}
397 	return noErr;
398 }
399 
400 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
401 
FrameToPacket(SInt64 inFrame,SInt64 & outPacket,UInt32 & outFrameOffsetInPacket)402 OSStatus AudioFileObject::FrameToPacket(SInt64 inFrame, SInt64& outPacket, UInt32& outFrameOffsetInPacket)
403 {
404 	if (mDataFormat.mFramesPerPacket == 0)
405 	{
406 		CompressedPacketTable* packetTable = GetPacketTable();
407 		if (!packetTable)
408 			return kAudioFileInvalidPacketOffsetError;
409 
410 		// search packet table
411 		AudioStreamPacketDescriptionExtended pext;
412 		memset(&pext, 0, sizeof(pext));
413 		pext.mFrameOffset = inFrame;
414 		CompressedPacketTable::iterator iter = std::lower_bound(packetTable->begin(), packetTable->end(), pext);
415 
416 		if (iter == packetTable->end())
417 			return kAudioFileInvalidPacketOffsetError;
418 
419 		if (iter > packetTable->begin()) --iter;
420 
421 		outPacket = iter - packetTable->begin();
422 		outFrameOffsetInPacket = (UInt32)(inFrame - iter->mFrameOffset);
423 	}
424 	else
425 	{
426 		outPacket = inFrame / mDataFormat.mFramesPerPacket;
427 		outFrameOffsetInPacket = (UInt32)(inFrame % mDataFormat.mFramesPerPacket);
428 	}
429 	return noErr;
430 }
431 
432 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
433 
PacketToByte(AudioBytePacketTranslation * abpt)434 OSStatus AudioFileObject::PacketToByte(AudioBytePacketTranslation* abpt)
435 {
436     if (abpt->mPacket < 0)
437         return kAudioFileInvalidPacketOffsetError;
438 
439 	if (mDataFormat.mBytesPerPacket == 0)
440 	{
441 		CompressedPacketTable* packetTable = GetPacketTable();
442 		if (!packetTable)
443 			return kAudioFileInvalidPacketOffsetError;
444 
445 		if (abpt->mPacket < GetPacketTableSize()) {
446 			abpt->mByte = (*packetTable)[(int)abpt->mPacket].mStartOffset;
447 			abpt->mFlags = 0;
448 		} else {
449 			SInt64 numPackets = packetTable->size();
450 			if (numPackets < 8)
451 				return 'more' /*kAudioFileStreamError_DataUnavailable*/ ;
452 
453 			const AudioStreamPacketDescriptionExtended lastPacket = (*packetTable)[numPackets - 1];
454 			SInt64 bytesReadSoFar = lastPacket.mStartOffset + lastPacket.mDataByteSize;
455 			double averageBytesPerPacket = (double)(bytesReadSoFar - GetDataOffset()) / (double)numPackets;
456 			abpt->mByte = (SInt64)floor((double)abpt->mPacket * averageBytesPerPacket);
457 			abpt->mFlags = kBytePacketTranslationFlag_IsEstimate;
458 		}
459 	}
460 	else
461 	{
462 		abpt->mByte = abpt->mPacket * mDataFormat.mBytesPerPacket;
463 		abpt->mFlags = 0;
464 	}
465 	return noErr;
466 }
467 
468 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
469 
byte_less_than(const AudioStreamPacketDescriptionExtended & a,const AudioStreamPacketDescriptionExtended & b)470 inline bool byte_less_than (const AudioStreamPacketDescriptionExtended& a, const AudioStreamPacketDescriptionExtended& b)
471 {
472 	return a.mStartOffset < b.mStartOffset;
473 }
474 
ByteToPacket(AudioBytePacketTranslation * abpt)475 OSStatus AudioFileObject::ByteToPacket(AudioBytePacketTranslation* abpt)
476 {
477     if (abpt->mByte < 0)
478         return kAudioFileInvalidPacketOffsetError;
479 
480 	if (mDataFormat.mBytesPerPacket == 0)
481 	{
482 		CompressedPacketTable* packetTable = GetPacketTable();
483 		if (!packetTable)
484 			return kAudioFileInvalidPacketOffsetError;
485 			// search packet table
486 		AudioStreamPacketDescriptionExtended pext;
487 		memset(&pext, 0, sizeof(pext));
488 		pext.mStartOffset = abpt->mByte;
489 		CompressedPacketTable::iterator iter = std::lower_bound(packetTable->begin(), packetTable->end(), pext, byte_less_than);
490 
491 		if (iter == packetTable->end()) {
492 			SInt64 numPackets = packetTable->size();
493 			if (numPackets < 8)
494 				return 'more' /*kAudioFileStreamError_DataUnavailable*/ ;
495 
496 			const AudioStreamPacketDescriptionExtended lastPacket = (*packetTable)[numPackets - 1];
497 			SInt64 bytesReadSoFar = lastPacket.mStartOffset + lastPacket.mDataByteSize;
498 			double averageBytesPerPacket = (double)(bytesReadSoFar - GetDataOffset()) / (double)numPackets;
499 
500 			double fpacket = (double)abpt->mByte / averageBytesPerPacket;
501 			abpt->mPacket = (SInt64)floor(fpacket);
502 			abpt->mByteOffsetInPacket = (UInt32)floor((fpacket - (double)abpt->mPacket) * averageBytesPerPacket);
503 			abpt->mFlags = kBytePacketTranslationFlag_IsEstimate;
504 
505 		} else {
506 			if (iter > packetTable->begin()) --iter;
507 			abpt->mPacket = iter - packetTable->begin();
508 			abpt->mByteOffsetInPacket = (UInt32)(abpt->mByte - iter->mStartOffset);
509 			abpt->mFlags = 0;
510 		}
511 	}
512 	else
513 	{
514 		abpt->mPacket = abpt->mByte / mDataFormat.mBytesPerPacket;
515 		abpt->mByteOffsetInPacket = (UInt32)(abpt->mByte % mDataFormat.mBytesPerPacket);
516 		abpt->mFlags = 0;
517 	}
518 	return noErr;
519 }
520 
521 
522 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
523 
524 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
525 
ReadBytes(Boolean inUseCache,SInt64 inStartingByte,UInt32 * ioNumBytes,void * outBuffer)526 OSStatus AudioFileObject::ReadBytes(
527 								Boolean			inUseCache,
528 								SInt64			inStartingByte,
529 								UInt32			*ioNumBytes,
530 								void			*outBuffer)
531 {
532     OSStatus		err = noErr;
533     UInt16			mode = SEEK_SET;
534 	SInt64 			fileOffset = mDataOffset + inStartingByte;
535     bool			readingPastEnd = false;
536 
537     FailWithAction((ioNumBytes == NULL) || (outBuffer == NULL), err = kAudio_ParamError,
538 		Bail, "invalid num bytes parameter");
539 
540 	//printf("inStartingByte %lld  GetNumBytes %lld\n", inStartingByte, GetNumBytes());
541 
542 	if (inStartingByte >= GetNumBytes())
543 	{
544 		*ioNumBytes = 0;
545 		return kAudioFileEndOfFileError;
546 	}
547 
548 	if ((fileOffset + *ioNumBytes) > (GetNumBytes() + mDataOffset))
549 	{
550 		*ioNumBytes = (UInt32)(GetNumBytes() + mDataOffset - fileOffset);
551 		readingPastEnd = true;
552 	}
553 	//printf("fileOffset %lld  mDataOffset %lld  readingPastEnd %d\n", fileOffset, mDataOffset, readingPastEnd);
554 
555     if (!inUseCache)
556         mode |= kAudioFileNoCacheMask;
557 
558     err = GetDataSource()->ReadBytes(mode, fileOffset, *ioNumBytes, outBuffer, ioNumBytes);
559 
560 	if (readingPastEnd && err == noErr)
561 		err = kAudioFileEndOfFileError;
562 
563 Bail:
564     return err;
565 }
566 
567 
568 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
569 
WriteBytes(Boolean inUseCache,SInt64 inStartingByte,UInt32 * ioNumBytes,const void * inBuffer)570 OSStatus AudioFileObject::WriteBytes(
571 								Boolean			inUseCache,
572 								SInt64			inStartingByte,
573 								UInt32			*ioNumBytes,
574 								const void		*inBuffer)
575 {
576     OSStatus		err = noErr;
577     UInt16			mode = SEEK_SET;
578 	bool			extendingTheAudioData;
579 
580 	if (!CanWrite()) return kAudioFilePermissionsError;
581 
582     FailWithAction((ioNumBytes == NULL) || (inBuffer == NULL), err = kAudioFileUnspecifiedError, Bail, "invalid parameters");
583 
584     // Do not try to write to a postion greater than 32 bits for some file types
585     // see if starting byte + ioNumBytes is greater than 32 bits
586     // if so, see if file type supports this and bail if not
587     err = IsValidFilePosition(inStartingByte + *ioNumBytes);
588     FailIf(err != noErr, Bail, "invalid file position");
589 
590     extendingTheAudioData = inStartingByte + *ioNumBytes > GetNumBytes();
591 
592     // if file is not optimized, then do not write data that would overwrite chunks following the sound data chunk
593     FailWithAction(	extendingTheAudioData && !IsOptimized(),
594                     err = kAudioFileNotOptimizedError, Bail, "Can't write more data until the file is optimized");
595 
596     if (!inUseCache)
597         mode |= kAudioFileNoCacheMask;
598 
599     err = GetDataSource()->WriteBytes(mode, mDataOffset + inStartingByte, *ioNumBytes,
600                         inBuffer, ioNumBytes);
601 
602     FailIf(err != noErr, Bail, "couldn't write new data");
603 
604     if (extendingTheAudioData) {
605         SInt64		nuEOF;						// Get the total bytes of audio data
606         SInt64		nuByteTotal;
607 
608 		err = GetDataSource()->GetSize(nuEOF);
609 		FailIf(err != noErr, Bail, "GetSize failed");
610 
611 		nuByteTotal = nuEOF - mDataOffset;
612 		err = UpdateNumBytes(nuByteTotal);
613     }
614 
615 Bail:
616     return err;
617 }
618 
619 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
620 
ReadPackets(Boolean inUseCache,UInt32 * outNumBytes,AudioStreamPacketDescription * outPacketDescriptions,SInt64 inStartingPacket,UInt32 * ioNumPackets,void * outBuffer)621 OSStatus AudioFileObject::ReadPackets(
622 								Boolean							inUseCache,
623 								UInt32							*outNumBytes,
624 								AudioStreamPacketDescription	*outPacketDescriptions,
625 								SInt64							inStartingPacket,
626 								UInt32  						*ioNumPackets,
627 								void							*outBuffer)
628 {
629 	// This only works with CBR. To suppport VBR you must override.
630     OSStatus		err = noErr;
631 
632     FailWithAction(outBuffer == NULL, err = kAudio_ParamError, Bail, "NULL buffer");
633 
634     FailWithAction((ioNumPackets == NULL) || (*ioNumPackets < 1), err = kAudio_ParamError, Bail, "invalid num packets parameter");
635 
636 	{
637 		UInt32			byteCount = *ioNumPackets * mDataFormat.mBytesPerPacket;
638 		SInt64			startingByte = inStartingPacket * mDataFormat.mBytesPerPacket;
639 
640 		err = ReadBytes (inUseCache, startingByte, &byteCount, outBuffer);
641 		if ((err == noErr) || (err == kAudioFileEndOfFileError))
642 		{
643 			if (byteCount != (*ioNumPackets * mDataFormat.mBytesPerPacket))
644 			{
645 				*ioNumPackets = byteCount / mDataFormat.mBytesPerPacket;
646 				byteCount = *ioNumPackets * mDataFormat.mBytesPerPacket;
647 			}
648 
649 			if (outNumBytes)
650 				*outNumBytes = byteCount;
651 
652 			if (err == kAudioFileEndOfFileError)
653 				err = noErr;
654 		}
655 	}
656 Bail:
657     return err;
658 }
659 
660 
661 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
662 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
663 
664 
665 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
666 
ReadPacketData(Boolean inUseCache,UInt32 * ioNumBytes,AudioStreamPacketDescription * outPacketDescriptions,SInt64 inStartingPacket,UInt32 * ioNumPackets,void * outBuffer)667 OSStatus AudioFileObject::ReadPacketData(
668 								Boolean							inUseCache,
669 								UInt32							*ioNumBytes,
670 								AudioStreamPacketDescription	*outPacketDescriptions,
671 								SInt64							inStartingPacket,
672 								UInt32  						*ioNumPackets,
673 								void							*outBuffer)
674 {
675 	OSStatus		err = noErr;
676 	FailWithAction(ioNumPackets == NULL || *ioNumPackets < 1, err = kAudio_ParamError, Bail, "invalid ioNumPackets parameter");
677 	FailWithAction(ioNumBytes   == NULL || *ioNumBytes   < 1, err = kAudio_ParamError, Bail, "invalid ioNumBytes parameter");
678 	if (mDataFormat.mBytesPerPacket) {
679 	 	// CBR
680 		FailWithAction(outBuffer    == NULL, err = kAudio_ParamError, Bail, "NULL buffer");
681 		UInt32 maxPackets = *ioNumBytes / mDataFormat.mBytesPerPacket;
682 		if (*ioNumPackets > maxPackets) *ioNumPackets = maxPackets;
683 
684 		if (outBuffer) {
685 			UInt32 byteCount = *ioNumPackets * mDataFormat.mBytesPerPacket;
686 			SInt64 startingByte = inStartingPacket * mDataFormat.mBytesPerPacket;
687 			err = ReadBytes (inUseCache, startingByte, &byteCount, outBuffer);
688 			if (err == noErr || err == kAudioFileEndOfFileError) {
689 				if (byteCount != (*ioNumPackets * mDataFormat.mBytesPerPacket)) {
690 					*ioNumPackets = byteCount / mDataFormat.mBytesPerPacket;
691 					byteCount = *ioNumPackets * mDataFormat.mBytesPerPacket;
692 				}
693 				*ioNumBytes = byteCount;
694 			}
695 		}
696 	} else {
697 		FailWithAction(outPacketDescriptions   == NULL, err = kAudio_ParamError, Bail, "invalid outPacketDescriptions parameter");
698 		err = ReadPacketDataVBR(inUseCache, ioNumBytes, outPacketDescriptions, inStartingPacket, ioNumPackets, outBuffer);
699 	}
700 Bail:
701 	return err;
702 }
703 
704 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
705 
ReadPacketDataVBR(Boolean inUseCache,UInt32 * ioNumBytes,AudioStreamPacketDescription * outPacketDescriptions,SInt64 inStartingPacket,UInt32 * ioNumPackets,void * outBuffer)706 OSStatus AudioFileObject::ReadPacketDataVBR(
707 								Boolean							inUseCache,
708 								UInt32							*ioNumBytes,
709 								AudioStreamPacketDescription	*outPacketDescriptions,
710 								SInt64							inStartingPacket,
711 								UInt32  						*ioNumPackets,
712 								void							*outBuffer)
713 {
714 	OSStatus err = ScanForPackets(inStartingPacket+1); // need to scan packets up to start
715 	if (err && err != kAudioFileEndOfFileError)
716 		return err;
717 
718 	SInt64 dataOffset = GetDataOffset();
719 
720 	CompressedPacketTable* packetTable = GetPacketTable();
721     if (!packetTable)
722 		return kAudioFileInvalidFileError;
723 
724 	SInt64 packetTableSize = GetPacketTableSize();
725 
726 	if (inStartingPacket >= packetTableSize) {
727 		*ioNumBytes = 0;
728 		*ioNumPackets = 0;
729 		return kAudioFileEndOfFileError;
730 	}
731 
732 	if (inStartingPacket + *ioNumPackets <= packetTableSize) {
733 		err = ReadPacketDataVBR_InTable(inUseCache, ioNumBytes, outPacketDescriptions, inStartingPacket, ioNumPackets, outBuffer);
734 	} else {
735 
736 		AudioStreamPacketDescription firstPacket = (*packetTable)[inStartingPacket];
737 		SInt64 firstPacketOffset = firstPacket.mStartOffset;
738 		UInt32 bytesRead = *ioNumBytes;
739 		SInt64 fileSize = 0;
740 		GetDataSource()->GetSize(fileSize);
741 		SInt64 remainingBytesInFile = fileSize - firstPacketOffset - dataOffset;
742 		if (bytesRead > remainingBytesInFile)
743 			bytesRead = (UInt32)remainingBytesInFile;
744 
745 		err = ReadBytes (inUseCache, firstPacketOffset, &bytesRead, outBuffer);
746 		if (err && err != kAudioFileEndOfFileError) {
747 			*ioNumBytes = 0;
748 			*ioNumPackets = 0;
749 			return err;
750 		}
751 
752 		Buffer_DataSource bufSrc(bytesRead, outBuffer, dataOffset + firstPacketOffset);
753 
754 		OSStatus scanErr = ScanForPackets(kScanToEnd, &bufSrc, false);
755 		if (scanErr && scanErr != kAudioFileEndOfFileError)
756 			return scanErr;
757 		packetTableSize = packetTable->size();
758 
759 		UInt32 numPacketsRead = 0;
760 		UInt32 endOfData = 0;
761 		SInt64 packetNumber = inStartingPacket;
762 		for (; numPacketsRead < *ioNumPackets && packetNumber < packetTableSize; ++numPacketsRead, ++packetNumber) {
763 			AudioStreamPacketDescription curPacket = (*packetTable)[numPacketsRead + inStartingPacket];
764 			SInt64 curPacketOffset = curPacket.mStartOffset - firstPacketOffset;
765 			SInt64 endOfPacket = curPacketOffset + curPacket.mDataByteSize;
766 			if (endOfPacket > bytesRead) break;
767 			endOfData = (UInt32)endOfPacket;
768 			outPacketDescriptions[numPacketsRead] = curPacket;
769 			outPacketDescriptions[numPacketsRead].mStartOffset = curPacketOffset;
770 		}
771 
772 		*ioNumBytes = endOfData;
773 		*ioNumPackets = numPacketsRead;
774 	}
775     return err;
776 }
777 
778 
779 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
HowManyPacketsCanBeReadIntoBuffer(UInt32 * ioNumBytes,SInt64 inStartingPacket,UInt32 * ioNumPackets)780 OSStatus AudioFileObject::HowManyPacketsCanBeReadIntoBuffer(UInt32* ioNumBytes, SInt64 inStartingPacket, UInt32 *ioNumPackets)
781 {
782 	CompressedPacketTable*	packetTable = GetPacketTable();
783 	SInt64 packetTableSize = GetPacketTableSize();
784 
785 	if (inStartingPacket + *ioNumPackets > (SInt64)packetTableSize) {
786 		*ioNumPackets = (UInt32)(packetTableSize - inStartingPacket);
787 	}
788 
789 	AudioStreamPacketDescription firstPacket = (*packetTable)[inStartingPacket];
790 
791 	if (*ioNumBytes < firstPacket.mDataByteSize) {
792 		*ioNumBytes = 0;
793 		*ioNumPackets = 0;
794 		return kAudio_ParamError;
795 	}
796 
797 	SInt64 lastPacketIndex = inStartingPacket + *ioNumPackets - 1;
798 	if (lastPacketIndex >= packetTableSize)
799 		lastPacketIndex = packetTableSize - 1;
800 
801 	AudioStreamPacketDescription lastPacket = (*packetTable)[lastPacketIndex];
802 
803 	SInt64 readBytes = lastPacket.mStartOffset + lastPacket.mDataByteSize - firstPacket.mStartOffset;
804 	if (readBytes <= *ioNumBytes) {
805 		*ioNumBytes = (UInt32)readBytes;
806 		return noErr;
807 	}
808 
809 	SInt64 lowBound = inStartingPacket;
810 	SInt64 highBound = lastPacketIndex + 1;
811 	SInt64 okIndex = lowBound;
812 	while (highBound >= lowBound) {
813 		SInt64 tryBound = (lowBound + highBound) >> 1;
814 		if (tryBound > lastPacketIndex)
815 			break;
816 		AudioStreamPacketDescription tryPacket = (*packetTable)[tryBound];
817 
818 		SInt64 readBytes = tryPacket.mStartOffset + tryPacket.mDataByteSize - firstPacket.mStartOffset;
819 
820 		if (readBytes > (SInt64)*ioNumBytes) {
821 			highBound = tryBound - 1;
822 		} else if (readBytes < (SInt64)*ioNumBytes) {
823 			okIndex = tryBound;
824 			lowBound = tryBound + 1;
825 		} else {
826 			okIndex = tryBound;
827 			break;
828 		}
829 	}
830 
831 	SInt64 numPackets = okIndex - inStartingPacket + 1;
832 	if (numPackets > *ioNumPackets) {
833 		numPackets = *ioNumPackets;
834 		okIndex = inStartingPacket + numPackets - 1;
835 	}
836 
837 	AudioStreamPacketDescription packet = (*packetTable)[okIndex];
838 	*ioNumBytes = (UInt32)(packet.mStartOffset + packet.mDataByteSize - firstPacket.mStartOffset);
839 	*ioNumPackets = (UInt32)numPackets;
840 	return noErr;
841 }
842 
843 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
844 
845 
846 
847 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
848 
ReadPacketDataVBR_InTable(Boolean inUseCache,UInt32 * ioNumBytes,AudioStreamPacketDescription * outPacketDescriptions,SInt64 inStartingPacket,UInt32 * ioNumPackets,void * outBuffer)849 OSStatus AudioFileObject::ReadPacketDataVBR_InTable(
850 								Boolean							inUseCache,
851 								UInt32							*ioNumBytes,
852 								AudioStreamPacketDescription	*outPacketDescriptions,
853 								SInt64							inStartingPacket,
854 								UInt32  						*ioNumPackets,
855 								void							*outBuffer)
856 {
857 	CompressedPacketTable* packetTable = GetPacketTable();
858     if (!packetTable)
859 		return kAudioFileInvalidFileError;
860 
861 	OSStatus err = HowManyPacketsCanBeReadIntoBuffer(ioNumBytes, inStartingPacket, ioNumPackets);
862 	if (err) return err;
863 
864 	AudioStreamPacketDescription firstPacket = (*packetTable)[inStartingPacket];
865 	SInt64 firstPacketOffset = firstPacket.mStartOffset;
866 	UInt32 bytesRead = *ioNumBytes;
867 
868 	if (outBuffer) {
869 		err = ReadBytes (inUseCache, firstPacketOffset, &bytesRead, outBuffer);
870 		if (err && err != kAudioFileEndOfFileError) {
871 			*ioNumBytes = 0;
872 			*ioNumPackets = 0;
873 			return err;
874 		}
875 		*ioNumBytes = bytesRead;
876 	}
877 
878 	// fill out packet descriptions
879 	if (outPacketDescriptions) {
880 		for (UInt32 i = 0; i < *ioNumPackets; i++) {
881 			AudioStreamPacketDescription curPacket = (*packetTable)[i + inStartingPacket];
882 			outPacketDescriptions[i] = curPacket;
883 			outPacketDescriptions[i].mStartOffset = curPacket.mStartOffset - firstPacketOffset;
884 		}
885 	}
886 
887     return err;
888 }
889 
890 
891 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
892 
WritePackets(Boolean inUseCache,UInt32 inNumBytes,const AudioStreamPacketDescription * inPacketDescriptions,SInt64 inStartingPacket,UInt32 * ioNumPackets,const void * inBuffer)893 OSStatus AudioFileObject::WritePackets(
894 									Boolean								inUseCache,
895                                     UInt32								inNumBytes,
896                                     const AudioStreamPacketDescription	*inPacketDescriptions,
897                                     SInt64								inStartingPacket,
898                                     UInt32								*ioNumPackets,
899                                     const void							*inBuffer)
900 {
901 	// This only works with CBR. To suppport VBR you must override.
902     OSStatus		err = noErr;
903 
904     FailWithAction(inStartingPacket > GetNumPackets(), err = kAudioFileInvalidPacketOffsetError, Bail, "write past end");
905     FailWithAction((ioNumPackets == NULL) || (inBuffer == NULL), err = kAudioFileUnspecifiedError, Bail, "invalid parameter");
906 
907 	{
908 		UInt32 byteCount = *ioNumPackets * mDataFormat.mBytesPerPacket;
909 		SInt64 startingByte = inStartingPacket * mDataFormat.mBytesPerPacket;
910 
911 		err = WriteBytes(inUseCache, startingByte, &byteCount, inBuffer);
912 		FailIf (err != noErr, Bail, "Write Bytes Failed");
913 
914 		if (byteCount != (*ioNumPackets * mDataFormat.mBytesPerPacket))
915 			*ioNumPackets = byteCount / mDataFormat.mBytesPerPacket;
916 	}
917 Bail:
918     return (err);
919 }
920 
921 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
922 
GetBitRate(UInt32 * outBitRate)923 OSStatus AudioFileObject::GetBitRate(			UInt32					*outBitRate)
924 {
925 
926 	if (!outBitRate) return kAudioFileUnspecifiedError;
927 
928 	UInt32 bytesPerPacket = GetDataFormat().mBytesPerPacket;
929 	UInt32 framesPerPacket = GetDataFormat().mFramesPerPacket;
930 	Float64 sampleRate = GetDataFormat().mSampleRate;
931 	const Float64 bitsPerByte = 8.;
932 
933 	if (bytesPerPacket && framesPerPacket) {
934 		*outBitRate = (UInt32)(bitsPerByte * (Float64)bytesPerPacket * sampleRate / (Float64)framesPerPacket);
935 	} else {
936 		SInt64 numPackets = GetNumPackets();
937 		SInt64 numBytes = GetNumBytes();
938 		SInt64 numFrames = 0;
939 
940 		if (framesPerPacket) {
941 			numFrames = numPackets * framesPerPacket;
942 		} else {
943 			// count frames
944 			CompressedPacketTable* packetTable = GetPacketTable();
945 			if (packetTable) {
946                 if (packetTable->size() != numPackets) {
947                     return kAudioFileInvalidFileError;
948                 }
949 #if !TARGET_OS_WIN32
950 				for (ssize_t i = 0; i < numPackets; i++)
951 #else
952 				for (int i = 0; i < numPackets; i++)
953 #endif
954 				{
955 					numFrames += (*packetTable)[i].mVariableFramesInPacket;
956 				}
957 			} else {
958 				return kAudioFileUnsupportedPropertyError;
959 			}
960 		}
961 
962         if (numFrames == 0 || (sampleRate == 0.)) {
963             *outBitRate = 0;
964             return noErr;
965         }
966 		Float64 duration = (Float64)numFrames / sampleRate;
967 		*outBitRate = (UInt32)(bitsPerByte * (Float64)numBytes / duration);
968 	}
969 
970 	return noErr;
971 }
972 
973 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
974 
GetMagicCookieDataSize(UInt32 * outDataSize,UInt32 * isWritable)975 OSStatus AudioFileObject::GetMagicCookieDataSize(
976 												UInt32					*outDataSize,
977 												UInt32					*isWritable)
978 {
979 	if (outDataSize)  *outDataSize = 0;
980 	if (isWritable)  *isWritable = 0;
981 	return kAudioFileUnsupportedPropertyError;
982 }
983 
984 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
985 
GetMagicCookieData(UInt32 * ioDataSize,void * ioPropertyData)986 OSStatus AudioFileObject::GetMagicCookieData(
987 												UInt32					*ioDataSize,
988 												void					*ioPropertyData)
989 {
990 	*ioDataSize = 0;
991 	return kAudioFileUnsupportedPropertyError;
992 }
993 
994 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
995 
SetMagicCookieData(UInt32,const void * inPropertyData)996 OSStatus AudioFileObject::SetMagicCookieData(	UInt32					/*inDataSize*/,
997 												const void				*inPropertyData)
998 {
999 	return kAudioFileInvalidChunkError;
1000 }
1001 
1002 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1003 
GetMarkerListSize(UInt32 * outDataSize,UInt32 * isWritable)1004 OSStatus AudioFileObject::GetMarkerListSize(
1005 												UInt32					*outDataSize,
1006 												UInt32					*isWritable)
1007 {
1008 	if (outDataSize) *outDataSize = 0;
1009 	if (isWritable) *isWritable = 0;
1010 	return kAudioFileUnsupportedPropertyError;
1011 }
1012 
1013 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1014 
GetMarkerList(UInt32 * ioDataSize,AudioFileMarkerList *)1015 OSStatus AudioFileObject::GetMarkerList(
1016 												UInt32					*ioDataSize,
1017 												AudioFileMarkerList*	/*ioPropertyData*/)
1018 {
1019 	*ioDataSize = 0;
1020 	return kAudioFileUnsupportedPropertyError;
1021 }
1022 
1023 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1024 
SetMarkerList(UInt32,const AudioFileMarkerList *)1025 OSStatus AudioFileObject::SetMarkerList(	UInt32						/*inDataSize*/,
1026 											const AudioFileMarkerList*  /*inPropertyData*/)
1027 {
1028 	return kAudioFileUnsupportedPropertyError;
1029 }
1030 
1031 
1032 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1033 
GetRegionListSize(UInt32 * outDataSize,UInt32 * isWritable)1034 OSStatus AudioFileObject::GetRegionListSize(
1035 												UInt32					*outDataSize,
1036 												UInt32					*isWritable)
1037 {
1038 	if (outDataSize) *outDataSize = 0;
1039 	if (isWritable) *isWritable = 0;
1040 	return kAudioFileUnsupportedPropertyError;
1041 }
1042 
1043 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1044 
GetRegionList(UInt32 * ioDataSize,AudioFileRegionList * ioPropertyData)1045 OSStatus AudioFileObject::GetRegionList(
1046 												UInt32					*ioDataSize,
1047 												AudioFileRegionList		*ioPropertyData)
1048 {
1049 	*ioDataSize = 0;
1050 	return kAudioFileUnsupportedPropertyError;
1051 }
1052 
1053 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1054 
SetRegionList(UInt32,const AudioFileRegionList *)1055 OSStatus AudioFileObject::SetRegionList(	UInt32						/*inDataSize*/,
1056 											const AudioFileRegionList*   /*inPropertyData*/)
1057 {
1058 	return kAudioFileUnsupportedPropertyError;
1059 }
1060 
1061 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1062 
GetChannelLayoutSize(UInt32 * outDataSize,UInt32 * isWritable)1063 OSStatus AudioFileObject::GetChannelLayoutSize(
1064 												UInt32					*outDataSize,
1065 												UInt32					*isWritable)
1066 {
1067 	if (outDataSize) *outDataSize = 0;
1068 	if (isWritable) *isWritable = 0;
1069 	return kAudioFileUnsupportedPropertyError;
1070 }
1071 
1072 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1073 
GetChannelLayout(UInt32 * ioDataSize,AudioChannelLayout *)1074 OSStatus AudioFileObject::GetChannelLayout(
1075 												UInt32						*ioDataSize,
1076 												AudioChannelLayout*			/*ioPropertyData*/)
1077 {
1078 	*ioDataSize = 0;
1079 	return kAudioFileUnsupportedPropertyError;
1080 }
1081 
1082 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1083 
SetChannelLayout(UInt32,const AudioChannelLayout *)1084 OSStatus AudioFileObject::SetChannelLayout(	UInt32						/*inDataSize*/,
1085 											const AudioChannelLayout*   /*inPropertyData*/)
1086 {
1087 	return kAudioFileUnsupportedPropertyError;
1088 }
1089 
1090 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1091 
GetInfoDictionarySize(UInt32 * outDataSize,UInt32 * isWritable)1092 OSStatus AudioFileObject::GetInfoDictionarySize(		UInt32						*outDataSize,
1093 									UInt32						*isWritable)
1094 {
1095 	if (outDataSize) *outDataSize = sizeof(CFDictionaryRef);
1096 	if (isWritable) *isWritable = 0;
1097 	return noErr;
1098 }
1099 
1100 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1101 
GetInfoDictionary(CACFDictionary * infoDict)1102 OSStatus AudioFileObject::GetInfoDictionary(CACFDictionary  *infoDict)
1103 {
1104 	Float64 fl;
1105 	if (GetEstimatedDuration(&fl) == noErr)
1106 		return AddDurationToInfoDictionary(infoDict, fl);
1107 
1108 	return kAudioFileUnsupportedPropertyError;
1109 }
1110 
1111 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1112 
SetInfoDictionary(CACFDictionary * infoDict)1113 OSStatus AudioFileObject::SetInfoDictionary(CACFDictionary *infoDict)
1114 {
1115 	return kAudioFileUnsupportedPropertyError;
1116 }
1117 
1118 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GetEstimatedDuration(Float64 * duration)1119 OSStatus AudioFileObject::GetEstimatedDuration(Float64*		duration)
1120 {
1121 	// calculate duration
1122 	AudioStreamBasicDescription		ASBD = GetDataFormat();
1123 
1124 	*duration  = (ASBD.mFramesPerPacket != 0) ? (GetNumPackets() * ASBD.mFramesPerPacket) / ASBD.mSampleRate : 0.0;
1125 
1126 	/*
1127 		For now, assume that any ASBD that has zero in the frames per packet field has been subclassed for this
1128 		method. i.e. A CAF file has a frame count in one of it's chunks.
1129 
1130 		MP3 has been subclassed because it guesstimates a duration so the entire file does not
1131 		need to be parsed in order to calculate the total frames.
1132 	*/
1133 
1134 	return noErr;
1135 
1136 }
1137 
1138 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1139 
GetPropertyInfo(AudioFilePropertyID inPropertyID,UInt32 * outDataSize,UInt32 * isWritable)1140 OSStatus AudioFileObject::GetPropertyInfo	(
1141                                         AudioFilePropertyID		inPropertyID,
1142                                         UInt32					*outDataSize,
1143                                         UInt32					*isWritable)
1144 {
1145     OSStatus		err = noErr;
1146     UInt32			writable = 0;
1147 
1148     switch (inPropertyID)
1149     {
1150 		case kAudioFilePropertyDeferSizeUpdates :
1151             if (outDataSize) *outDataSize = sizeof(UInt32);
1152             writable = 1;
1153             break;
1154 
1155         case kAudioFilePropertyFileFormat:
1156             if (outDataSize) *outDataSize = sizeof(UInt32);
1157             writable = 0;
1158             break;
1159 
1160         case kAudioFilePropertyDataFormat:
1161             if (outDataSize) *outDataSize = sizeof(AudioStreamBasicDescription);
1162             writable = 1;
1163             break;
1164 
1165 		case kAudioFilePropertyFormatList:
1166 			err = GetFormatListInfo(*outDataSize, writable);
1167             break;
1168 
1169 		case kAudioFilePropertyPacketSizeUpperBound:
1170         case kAudioFilePropertyIsOptimized:
1171         case kAudioFilePropertyMaximumPacketSize:
1172             if (outDataSize) *outDataSize = sizeof(UInt32);
1173             writable = 0;
1174             break;
1175 
1176         case kAudioFilePropertyAudioDataByteCount:
1177         case kAudioFilePropertyAudioDataPacketCount:
1178             writable = 1;
1179             if (outDataSize) *outDataSize = sizeof(SInt64);
1180             break;
1181 
1182 		case kAudioFilePropertyDataOffset:
1183             writable = 0;
1184             if (outDataSize) *outDataSize = sizeof(SInt64);
1185             break;
1186 
1187 		case kAudioFilePropertyBitRate:
1188             writable = 0;
1189             if (outDataSize) *outDataSize = sizeof(UInt32);
1190 			break;
1191 
1192 		case kAudioFilePropertyMagicCookieData:
1193             err = GetMagicCookieDataSize(outDataSize, &writable);
1194 			break;
1195 
1196 		case kAudioFilePropertyMarkerList :
1197             err = GetMarkerListSize(outDataSize, &writable);
1198 			break;
1199 
1200 		case kAudioFilePropertyRegionList :
1201             err = GetRegionListSize(outDataSize, &writable);
1202 			break;
1203 
1204 		case kAudioFilePropertyChannelLayout :
1205             err = GetChannelLayoutSize(outDataSize, &writable);
1206 			break;
1207 
1208 		case kAudioFilePropertyPacketToFrame :
1209 		case kAudioFilePropertyFrameToPacket :
1210             if (outDataSize) *outDataSize = sizeof(AudioFramePacketTranslation);
1211             writable = 0;
1212 			break;
1213 
1214 		case kAudioFilePropertyPacketToByte :
1215 		case kAudioFilePropertyByteToPacket :
1216             if (outDataSize) *outDataSize = sizeof(AudioBytePacketTranslation);
1217             writable = 0;
1218 			break;
1219 
1220         case kAudioFilePropertyInfoDictionary :
1221             err = GetInfoDictionarySize(outDataSize, &writable);
1222             break;
1223 
1224         case kTEMPAudioFilePropertySoundCheckDictionary :
1225             err = GetSoundCheckDictionarySize(outDataSize, &writable);
1226             break;
1227 
1228 		case kTEMPAudioFilePropertyGenerateLoudnessInfo :
1229             err = GetLoudnessInfoSize(outDataSize, &writable);
1230             writable = 0;
1231             break;
1232 
1233 		case kTEMPAudioFilePropertyLoudnessInfo :
1234             err = GetLoudnessInfoSize(outDataSize, &writable);
1235             break;
1236 
1237 		case kAudioFilePropertyEstimatedDuration :
1238             if (outDataSize) *outDataSize = sizeof(Float64);
1239             writable = 0;
1240 			break;
1241 
1242 		case 'LYRC':
1243 			if (outDataSize) *outDataSize = sizeof(CFStringRef);
1244 			if (isWritable) *isWritable = 0;
1245 			break;
1246 
1247 		case 'eof?':
1248 			if (outDataSize) *outDataSize = sizeof(UInt32);
1249 			if (isWritable) *isWritable = 0;
1250 			break;
1251 
1252 		case 'sbtd' /*kAudioFilePropertySourceBitDepth*/ :
1253 			if (outDataSize) *outDataSize = sizeof(SInt32);
1254 			if (isWritable) *isWritable = CanWrite();
1255 			break;
1256 
1257         default:
1258             writable = 0;
1259             err = kAudioFileUnsupportedPropertyError;
1260             break;
1261     }
1262 
1263     if (isWritable)
1264         *isWritable = writable;
1265     return (err);
1266 }
1267 
1268 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1269 
GetProperty(AudioFilePropertyID inPropertyID,UInt32 * ioDataSize,void * ioPropertyData)1270 OSStatus	AudioFileObject::GetProperty(
1271                                     AudioFilePropertyID		inPropertyID,
1272                                     UInt32					*ioDataSize,
1273                                     void					*ioPropertyData)
1274 {
1275     OSStatus		err = noErr;
1276 	UInt32			neededSize;
1277     UInt32			writable;
1278 
1279     switch (inPropertyID)
1280     {
1281         case kAudioFilePropertyFileFormat:
1282             FailWithAction(*ioDataSize != sizeof(UInt32),
1283 				err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1284 
1285             *(UInt32 *) ioPropertyData = GetFileType();
1286             break;
1287 
1288 		case kAudioFilePropertyFormatList:
1289 			err = GetFormatList(*ioDataSize, (AudioFormatListItem*)ioPropertyData);
1290             break;
1291 
1292         case kAudioFilePropertyDataFormat:
1293             FailWithAction(*ioDataSize != sizeof(AudioStreamBasicDescription),
1294 				err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1295 
1296             memcpy(ioPropertyData, &mDataFormat, sizeof(AudioStreamBasicDescription));
1297             break;
1298 		case kAudioFilePropertyDataOffset:
1299             FailWithAction(*ioDataSize != sizeof(SInt64),
1300 				err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1301             *(SInt64 *) ioPropertyData = mDataOffset;
1302 			break;
1303         case kAudioFilePropertyIsOptimized:
1304             FailWithAction(*ioDataSize != sizeof(UInt32),
1305 				err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1306             *(UInt32 *) ioPropertyData = mIsOptimized;
1307             break;
1308 
1309         case kAudioFilePropertyAudioDataByteCount:
1310             FailWithAction(*ioDataSize != sizeof(SInt64),
1311 				err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1312             *(SInt64 *)ioPropertyData = GetNumBytes();
1313             break;
1314 
1315         case kAudioFilePropertyAudioDataPacketCount:
1316             FailWithAction(*ioDataSize != sizeof(SInt64),
1317 				err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1318             *(SInt64 *)ioPropertyData = GetNumPackets();
1319             break;
1320 
1321 		case kAudioFilePropertyPacketSizeUpperBound:
1322             FailWithAction(*ioDataSize != sizeof(UInt32),
1323 				err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1324             *(UInt32 *)ioPropertyData = GetPacketSizeUpperBound();
1325             break;
1326 
1327         case kAudioFilePropertyMaximumPacketSize:
1328             FailWithAction(*ioDataSize != sizeof(UInt32),
1329 				err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1330             *(UInt32 *)ioPropertyData = FindMaximumPacketSize();
1331             break;
1332 
1333 
1334          case kAudioFilePropertyBitRate:
1335             FailWithAction(*ioDataSize != sizeof(UInt32),
1336 				err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1337 			err = GetBitRate((UInt32*)ioPropertyData);
1338             break;
1339 
1340          case kAudioFilePropertyMagicCookieData:
1341 
1342 			err = GetMagicCookieData(ioDataSize, ioPropertyData);
1343             break;
1344 
1345 		case kAudioFilePropertyMarkerList :
1346             err = GetMarkerList(ioDataSize, static_cast<AudioFileMarkerList*>(ioPropertyData));
1347 			break;
1348 
1349 		case kAudioFilePropertyRegionList :
1350 			memset(ioPropertyData, 0, *ioDataSize);
1351             err = GetRegionList(ioDataSize, static_cast<AudioFileRegionList*>(ioPropertyData));
1352 			break;
1353 
1354 		case kAudioFilePropertyChannelLayout :
1355 			err = GetChannelLayoutSize(&neededSize, &writable);
1356             FailIf(err, Bail, "GetChannelLayoutSize failed");
1357             FailWithAction(*ioDataSize != neededSize, err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1358 
1359             err = GetChannelLayout(ioDataSize, static_cast<AudioChannelLayout*>(ioPropertyData));
1360 			break;
1361 
1362 		case kAudioFilePropertyDeferSizeUpdates :
1363             FailWithAction(*ioDataSize != sizeof(UInt32),
1364 				err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1365 
1366             *(UInt32 *) ioPropertyData = DeferSizeUpdates();
1367             break;
1368 
1369 		case kAudioFilePropertyPacketToFrame :
1370 		{
1371             FailWithAction(*ioDataSize != sizeof(AudioFramePacketTranslation),
1372 				err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1373 
1374 			AudioFramePacketTranslation* afpt = (AudioFramePacketTranslation*)ioPropertyData;
1375 			err = PacketToFrame(afpt->mPacket, afpt->mFrame);
1376 			break;
1377 		}
1378 		case kAudioFilePropertyFrameToPacket :
1379 		{
1380             FailWithAction(*ioDataSize != sizeof(AudioFramePacketTranslation),
1381 				err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1382 
1383 			AudioFramePacketTranslation* afpt = (AudioFramePacketTranslation*)ioPropertyData;
1384 			err = FrameToPacket(afpt->mFrame, afpt->mPacket, afpt->mFrameOffsetInPacket);
1385 			break;
1386 		}
1387 
1388 		case kAudioFilePropertyPacketToByte :
1389 		{
1390             FailWithAction(*ioDataSize != sizeof(AudioBytePacketTranslation),
1391 				err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1392 
1393 			AudioBytePacketTranslation* abpt = (AudioBytePacketTranslation*)ioPropertyData;
1394 			err = PacketToByte(abpt);
1395 			break;
1396 		}
1397 		case kAudioFilePropertyByteToPacket :
1398 		{
1399             FailWithAction(*ioDataSize != sizeof(AudioBytePacketTranslation),
1400 				err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1401 
1402 			AudioBytePacketTranslation* abpt = (AudioBytePacketTranslation*)ioPropertyData;
1403 			err = ByteToPacket(abpt);
1404 			break;
1405 		}
1406 
1407         case kAudioFilePropertyInfoDictionary :
1408 		{
1409             FailWithAction(*ioDataSize != sizeof(CFDictionaryRef),
1410 				err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1411 
1412 			CACFDictionary		afInfoDictionary(true);
1413 
1414             err = GetInfoDictionary(&afInfoDictionary);
1415 
1416 			if (!err)
1417 			{
1418 				*(CFMutableDictionaryRef *)ioPropertyData = afInfoDictionary.CopyCFMutableDictionary();
1419 			}
1420             break;
1421 		}
1422 
1423         case kTEMPAudioFilePropertySoundCheckDictionary :
1424 		{
1425             FailWithAction(*ioDataSize != sizeof(CFDictionaryRef),
1426 				err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1427 
1428 			CACFDictionary		afInfoDictionary(true);
1429 
1430             err = GetSoundCheckDictionary(&afInfoDictionary);
1431             if (err) {
1432 				OSStatus err2 = GetSoundCheckDictionaryFromLoudnessInfo(&afInfoDictionary);
1433 				if (err2 == noErr) err = noErr; // else report original error from GetSoundCheckDictionary.
1434 			}
1435 
1436 			if (!err)
1437 			{
1438 				*(CFMutableDictionaryRef *)ioPropertyData = afInfoDictionary.CopyCFMutableDictionary();
1439 			}
1440             break;
1441 		}
1442 
1443         case kTEMPAudioFilePropertyLoudnessInfo :
1444 		{
1445             FailWithAction(*ioDataSize != sizeof(CFDictionaryRef),
1446 				err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1447 
1448 			CACFDictionary		afInfoDictionary(true);
1449 
1450             err = GetLoudnessInfo(&afInfoDictionary);
1451             if (err) {
1452 				OSStatus err2 = GetLoudnessInfoFromSoundCheckDictionary(&afInfoDictionary);
1453 				if (err2 == noErr) err = noErr; // else report original error from GetLoudnessInfo.
1454 			}
1455 
1456 			if (!err)
1457 			{
1458 				*(CFMutableDictionaryRef *)ioPropertyData = afInfoDictionary.CopyCFMutableDictionary();
1459 			}
1460             break;
1461 		}
1462 
1463 		case kTEMPAudioFilePropertyGenerateLoudnessInfo :
1464 		{
1465             FailWithAction(*ioDataSize != sizeof(CFDictionaryRef),
1466 				err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1467 
1468 			CACFDictionary		afInfoDictionary(true);
1469 
1470             err = GenerateLoudnessInfo(&afInfoDictionary);
1471 
1472 			if (!err)
1473 			{
1474 				*(CFMutableDictionaryRef *)ioPropertyData = afInfoDictionary.CopyCFMutableDictionary();
1475 			}
1476             break;
1477 		}
1478 
1479 		case kAudioFilePropertyEstimatedDuration :
1480 		{
1481             FailWithAction(*ioDataSize != sizeof(Float64),
1482 				err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1483 
1484 			err = GetEstimatedDuration((Float64*)ioPropertyData);
1485 			break;
1486 		}
1487 
1488         case 'LYRC' :
1489             if (*ioDataSize < sizeof(CFStringRef))
1490                 return kAudioFileBadPropertySizeError;
1491 
1492 			*ioDataSize = sizeof(CFStringRef);
1493 			err = GetLyrics((CFStringRef*) ioPropertyData);
1494 			break;
1495 
1496 		case 'eof?' :
1497 		{
1498             if (*ioDataSize != sizeof(UInt32))
1499                 return kAudioFileBadPropertySizeError;
1500 
1501 			SInt64 pos;
1502 			err = GetDataSource()->GetPos(pos);
1503 			if (err) break;
1504 
1505 			SInt64 endOfData = GetDataOffset() + GetNumBytes();
1506 			*(UInt32*)ioPropertyData = pos >= endOfData;
1507 
1508 			break;
1509 		}
1510 		case 'sbtd' /*kAudioFilePropertySourceBitDepth*/ :
1511 		{
1512             if (*ioDataSize != sizeof(SInt32))
1513                 return kAudioFileBadPropertySizeError;
1514 
1515 			SInt32 outValue = 0;
1516 			err = GetSourceBitDepth(outValue);
1517 			if ((err || outValue == 0) && GetDataFormat().mFormatID == kAudioFormatLinearPCM) {
1518 				// if there was no stored source bit depth, and this file is LPCM, then report this file's bit depth.
1519 				err = noErr;
1520 				outValue = GetDataFormat().mBitsPerChannel;
1521 				if (GetDataFormat().mFormatFlags & kAudioFormatFlagIsFloat)
1522 					outValue = -outValue;
1523 			} else if (err)
1524 				break;
1525 
1526 			*(SInt32 *) ioPropertyData = outValue;
1527 
1528 			break;
1529 		}
1530 		default:
1531             err = kAudioFileUnsupportedPropertyError;
1532             break;
1533     }
1534 
1535 Bail:
1536     return err;
1537 }
1538 
1539 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1540 
SetProperty(AudioFilePropertyID inPropertyID,UInt32 inDataSize,const void * inPropertyData)1541 OSStatus	AudioFileObject::SetProperty(
1542                                     AudioFilePropertyID		inPropertyID,
1543                                     UInt32					inDataSize,
1544                                     const void				*inPropertyData)
1545 {
1546     OSStatus		err = noErr;
1547 
1548     switch (inPropertyID)
1549     {
1550         case kAudioFilePropertyDataFormat:
1551             FailWithAction(inDataSize != sizeof(AudioStreamBasicDescription),
1552 				err = kAudioFileBadPropertySizeError, Bail, "Incorrect data size");
1553             err = UpdateDataFormat((AudioStreamBasicDescription *) inPropertyData);
1554 			break;
1555 		case kAudioFilePropertyFormatList:
1556 			err = SetFormatList(inDataSize, (AudioFormatListItem*)inPropertyData);
1557             break;
1558 
1559         case kAudioFilePropertyAudioDataByteCount: {
1560             FailWithAction(inDataSize != sizeof(SInt64), err = kAudioFileBadPropertySizeError, Bail, "Incorrect data size");
1561             SInt64 numBytes = *(SInt64 *) inPropertyData;
1562 			if (numBytes > GetNumBytes()) {
1563 				// can't use this to increase data size.
1564 				return kAudioFileOperationNotSupportedError;
1565 			}
1566 			UInt32 saveDefer = DeferSizeUpdates();
1567 			SetDeferSizeUpdates(0); // force an update.
1568 			err = UpdateNumBytes(numBytes);
1569 			SetDeferSizeUpdates(saveDefer);
1570 		} break;
1571 
1572 		case kAudioFilePropertyAudioDataPacketCount: {
1573 			SInt64 numPackets = *(SInt64 *) inPropertyData;
1574 			if (numPackets > GetNumPackets()) {
1575 				// can't use this to increase data size.
1576 				return kAudioFileOperationNotSupportedError;
1577 			}
1578 			err = UpdateNumPackets(numPackets);
1579 		} break;
1580 
1581 		case kAudioFilePropertyMagicCookieData:
1582 			err = SetMagicCookieData(inDataSize, inPropertyData);
1583 			break;
1584 
1585 
1586 		case kAudioFilePropertyMarkerList :
1587             err = SetMarkerList(inDataSize, static_cast<const AudioFileMarkerList*>(inPropertyData));
1588 			break;
1589 
1590 		case kAudioFilePropertyRegionList :
1591             err = SetRegionList(inDataSize, static_cast<const AudioFileRegionList*>(inPropertyData));
1592 			break;
1593 
1594 		case kAudioFilePropertyChannelLayout :
1595             err = SetChannelLayout(inDataSize, static_cast<const AudioChannelLayout*>(inPropertyData));
1596 			break;
1597 
1598 		case kAudioFilePropertyDeferSizeUpdates :
1599             FailWithAction(inDataSize != sizeof(UInt32),
1600 				err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1601             SetDeferSizeUpdates(*(UInt32 *) inPropertyData);
1602             break;
1603 
1604         case kAudioFilePropertyInfoDictionary :
1605 		{
1606             FailWithAction(inDataSize != sizeof(CFDictionaryRef),
1607 				err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1608 
1609 			// pass the SetInfoDictionary a CACFDictionary object made with the provided CFDictionaryRef
1610 			// Let the caller release their own CFObject so pass false for th erelease parameter
1611 			CACFDictionary		afInfoDictionary(*(CFDictionaryRef *)inPropertyData, false);
1612             err = SetInfoDictionary(&afInfoDictionary);
1613 
1614             break;
1615 		}
1616 
1617         case kTEMPAudioFilePropertySoundCheckDictionary :
1618 		{
1619             FailWithAction(inDataSize != sizeof(CFDictionaryRef),
1620 				err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1621 
1622 			// pass the SetInfoDictionary a CACFDictionary object made with the provided CFDictionaryRef
1623 			// Let the caller release their own CFObject so pass false for the release parameter
1624 			CACFDictionary		afInfoDictionary(*(CFDictionaryRef *)inPropertyData, false);
1625             err = SetSoundCheckDictionary(&afInfoDictionary);
1626 
1627             break;
1628 		}
1629 
1630         case kTEMPAudioFilePropertyLoudnessInfo :
1631 		{
1632             FailWithAction(inDataSize != sizeof(CFDictionaryRef),
1633 				err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1634 
1635 			// pass the SetInfoDictionary a CACFDictionary object made with the provided CFDictionaryRef
1636 			// Let the caller release their own CFObject so pass false for the release parameter
1637 			CACFDictionary		afInfoDictionary(*(CFDictionaryRef *)inPropertyData, false);
1638             err = SetLoudnessInfo(&afInfoDictionary);
1639 
1640             break;
1641 		}
1642 
1643   		case 'sbtd' /*kAudioFilePropertySourceBitDepth*/ :
1644 		{
1645             FailWithAction(inDataSize != sizeof(SInt32),
1646 				err = kAudioFileBadPropertySizeError, Bail, "inDataSize is wrong");
1647 
1648 			SInt32 inValue = *(SInt32 *)inPropertyData;
1649 			err = SetSourceBitDepth(inValue);
1650 
1651 			break;
1652 		}
1653 
1654       default:
1655             err = kAudioFileUnsupportedPropertyError;
1656 		break;
1657     }
1658 
1659 Bail:
1660     return err;
1661 }
1662 
1663 
1664 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1665 
SetDataFormat(const AudioStreamBasicDescription * inStreamFormat)1666 OSStatus AudioFileObject::SetDataFormat(const AudioStreamBasicDescription* inStreamFormat)
1667 {
1668 	OSStatus err = noErr;
1669 
1670 	if (!IsDataFormatValid(inStreamFormat))
1671 		return kAudioFileUnsupportedDataFormatError;
1672 
1673 	if (!IsDataFormatSupported(inStreamFormat))
1674 		return kAudioFileUnsupportedDataFormatError;
1675 
1676 	UInt32 prevBytesPerPacket = mDataFormat.mBytesPerPacket;
1677 
1678 	mDataFormat = *inStreamFormat;
1679 
1680 	// if CBR and bytes per packet changes, we need to change the number of packets we think we have.
1681 	if (mDataFormat.mBytesPerPacket && mDataFormat.mBytesPerPacket != prevBytesPerPacket)
1682 	{
1683 		SInt64 numPackets = GetNumBytes() / mDataFormat.mBytesPerPacket;
1684 		SetNumPackets(numPackets);
1685 		SetMaximumPacketSize(mDataFormat.mBytesPerPacket);
1686 
1687 		if (!mFirstSetFormat)
1688 			SizeChanged();
1689 	}
1690 
1691 	mFirstSetFormat = false;
1692 
1693 	return err;
1694 }
1695 
1696 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1697 
GetFormatListInfo(UInt32 & outDataSize,UInt32 & outWritable)1698 OSStatus AudioFileObject::GetFormatListInfo(	UInt32				&outDataSize,
1699 													UInt32				&outWritable)
1700 {
1701 	// default implementation is to just return the data format
1702 	outDataSize = sizeof(AudioFormatListItem);
1703 	outWritable = false;
1704 	return noErr;
1705 }
1706 
1707 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1708 
GetFormatList(UInt32 & ioDataSize,AudioFormatListItem * ioPropertyData)1709 OSStatus AudioFileObject::GetFormatList(	UInt32									&ioDataSize,
1710 												AudioFormatListItem						*ioPropertyData)
1711 {
1712 	// default implementation is to just return the data format
1713 	if (ioDataSize < sizeof(AudioFormatListItem))
1714 		return kAudioFileBadPropertySizeError;
1715 
1716 	AudioFormatListItem afli;
1717 	afli.mASBD = mDataFormat;
1718 	AudioChannelLayoutTag layoutTag = /*kAudioChannelLayoutTag_Unknown*/ 0xFFFF0000 | mDataFormat.mChannelsPerFrame;
1719 	UInt32 layoutSize, isWritable;
1720 	OSStatus err = GetChannelLayoutSize(&layoutSize, &isWritable);
1721 	if (err == noErr)
1722 	{
1723 		CAAutoFree<AudioChannelLayout> layout;
1724 		layout.allocBytes(layoutSize);
1725 		err = GetChannelLayout(&layoutSize, layout());
1726 		if (err == noErr) {
1727 			layoutTag = layout->mChannelLayoutTag;
1728 		}
1729 	}
1730 	afli.mChannelLayoutTag = layoutTag;
1731 
1732 	memcpy(ioPropertyData, &afli, sizeof(AudioFormatListItem));
1733 
1734 	ioDataSize = sizeof(AudioFormatListItem);
1735 	return noErr;
1736 }
1737 
1738 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1739 
SetFormatList(UInt32 inDataSize,const AudioFormatListItem * inPropertyData)1740 OSStatus AudioFileObject::SetFormatList(	UInt32									inDataSize,
1741 											const AudioFormatListItem				*inPropertyData)
1742 {
1743 	return kAudioFileOperationNotSupportedError;
1744 }
1745 
1746 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1747 
UpdateDataFormat(const AudioStreamBasicDescription * inStreamFormat)1748 OSStatus AudioFileObject::UpdateDataFormat(const AudioStreamBasicDescription* inStreamFormat)
1749 {
1750 	return SetDataFormat(inStreamFormat);
1751 }
1752 
1753 
1754 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1755 
IsDataFormatValid(AudioStreamBasicDescription const * inDesc)1756 Boolean AudioFileObject::IsDataFormatValid(AudioStreamBasicDescription const* inDesc)
1757 {
1758 	if (inDesc->mSampleRate < 0.)
1759 		return false;
1760 
1761 	if (inDesc->mSampleRate > 3e6)
1762 		return false;
1763 
1764 	if (inDesc->mChannelsPerFrame < 1 || inDesc->mChannelsPerFrame > 0x000FFFFF)
1765 		return false;
1766 
1767 	if (inDesc->mFormatID == kAudioFormatLinearPCM)
1768 	{
1769 		if (inDesc->mBitsPerChannel < 1 || inDesc->mBitsPerChannel > 64)
1770 			return false;
1771 
1772 		if (inDesc->mFramesPerPacket != 1)
1773 			return false;
1774 
1775 		if (inDesc->mBytesPerPacket == 0)
1776 			return false;
1777 
1778 		if (inDesc->mBytesPerFrame != inDesc->mBytesPerPacket)
1779 			return false;
1780 
1781 		// [3605260] we assume here that a packet is an integer number of frames.
1782 		UInt32 minimumBytesPerPacket = (inDesc->mBitsPerChannel * inDesc->mChannelsPerFrame + 7) / 8;
1783 		if (inDesc->mBytesPerPacket < minimumBytesPerPacket)
1784 			return false;
1785 	}
1786 	return true;
1787 }
1788 
1789 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1790 
SetDataSource(DataSource * inDataSource)1791 void AudioFileObject::SetDataSource(DataSource* inDataSource)
1792 {
1793 	if (mDataSource != inDataSource) {
1794 		delete mDataSource;
1795 		mDataSource = inDataSource;
1796 	}
1797 }
1798 
1799 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1800 
SetURL(CFURLRef inURL)1801 void	AudioFileObject::SetURL (CFURLRef inURL)
1802 {
1803 	if (mFileRef == inURL) return;
1804 	if (inURL) CFRetain (inURL);
1805 	if (mFileRef) CFRelease(mFileRef);
1806 	mFileRef = inURL;
1807 }
1808 
OpenFile(SInt8 inPermissions,int inFD)1809 OSStatus AudioFileObject::OpenFile(SInt8 inPermissions, int inFD)
1810 {
1811 	OSStatus err = noErr;
1812 
1813 	SetDataSource(new Cached_DataSource(new UnixFile_DataSource(inFD, inPermissions, true)));
1814 
1815 	mFileD = inFD;
1816 	SetPermissions (inPermissions);
1817 
1818 	return err;
1819 }
1820 
CreateDataFile(CFURLRef inFileRef,int & outFileD)1821 OSStatus AudioFileObject::CreateDataFile (CFURLRef	inFileRef, int	&outFileD)
1822 {
1823 	UInt8 fPath[FILENAME_MAX];
1824 	if (!CFURLGetFileSystemRepresentation (inFileRef, true, fPath, FILENAME_MAX))
1825 		return kAudio_FileNotFoundError;
1826 
1827 	struct stat stbuf;
1828 	if (stat ((const char*)fPath, &stbuf) == 0)
1829 		return kAudioFilePermissionsError;
1830 
1831 #if TARGET_OS_WIN32
1832 	int filePerms = S_IREAD | S_IWRITE;
1833 	int flags = O_CREAT | O_EXCL | O_RDWR | O_BINARY;
1834 #else
1835 	mode_t filePerms = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
1836 	int flags = O_CREAT | O_EXCL | O_RDWR;
1837 #endif
1838 	outFileD = open((const char*)fPath, flags, filePerms);
1839 	if (outFileD < 0)
1840 		return AudioFileTranslateErrno(errno);
1841 
1842 	return noErr;
1843 }
1844 
AddDurationToInfoDictionary(CACFDictionary * infoDict,Float64 & inDuration)1845 OSStatus AudioFileObject::AddDurationToInfoDictionary(CACFDictionary *infoDict, Float64 &inDuration)
1846 {
1847 #if !TARGET_OS_WIN32
1848 	CFLocaleRef currentLocale = CFLocaleGetSystem();
1849 	CFNumberFormatterRef numberFormatter = NULL;
1850 	numberFormatter = CFNumberFormatterCreate(kCFAllocatorDefault, currentLocale, kCFNumberFormatterDecimalStyle);
1851 	CFStringRef cfStr = CFNumberFormatterCreateStringWithValue( kCFAllocatorDefault, numberFormatter, kCFNumberFloat64Type, &inDuration);
1852 	if (cfStr)
1853 	{
1854 		if (CFStringGetLength(cfStr) != 0)
1855 			infoDict->AddString(CFSTR(kAFInfoDictionary_ApproximateDurationInSeconds), cfStr);
1856 		CFRelease(cfStr);
1857 	}
1858 	CFRelease(numberFormatter);
1859 #endif
1860 	return noErr;
1861 }
1862 
SizeChanged()1863 OSStatus AudioFileObject::SizeChanged()
1864 {
1865 	OSStatus err = noErr;
1866 	if (mPermissions & kAudioFileWritePermission)
1867 	{
1868 		if (DeferSizeUpdates())
1869 			SetNeedsSizeUpdate(true);
1870 		else
1871 			err = UpdateSize();
1872 	}
1873 	return err;
1874 }
1875 
UpdateSizeIfNeeded()1876 OSStatus AudioFileObject::UpdateSizeIfNeeded()
1877 {
1878 	if (GetNeedsSizeUpdate())
1879 	{
1880 		OSStatus err = UpdateSize();
1881 		if (err) return err;
1882 		SetNeedsSizeUpdate(false);
1883 	}
1884 	return noErr;
1885 }
1886 
CountUserData(UInt32,UInt32 *)1887 OSStatus AudioFileObject::CountUserData(	UInt32					/*inUserDataID*/,
1888 											UInt32*					/*outNumberItems*/)
1889 {
1890 	return kAudioFileOperationNotSupportedError;
1891 }
1892 
GetUserDataSize(UInt32,UInt32,UInt32 *)1893 OSStatus AudioFileObject::GetUserDataSize(  UInt32					/*inUserDataID*/,
1894 											UInt32					/*inIndex*/,
1895 											UInt32*					/*outDataSize*/)
1896 {
1897 	return kAudioFileOperationNotSupportedError;
1898 }
1899 
GetUserData(UInt32,UInt32,UInt32 *,void *)1900 OSStatus AudioFileObject::GetUserData(		UInt32					/*inUserDataID*/,
1901 											UInt32					/*inIndex*/,
1902 											UInt32*					/*ioDataSize*/,
1903 											void*					/*ioUserData*/)
1904 {
1905 	return kAudioFileOperationNotSupportedError;
1906 }
1907 
SetUserData(UInt32,UInt32,UInt32,const void *)1908 OSStatus AudioFileObject::SetUserData(		UInt32					/*inUserDataID*/,
1909 											UInt32					/*inIndex*/,
1910 											UInt32					/*inDataSize*/,
1911 											const void*				/*inUserData*/)
1912 {
1913 	return kAudioFileOperationNotSupportedError;
1914 }
1915 
RemoveUserData(UInt32,UInt32)1916 OSStatus AudioFileObject::RemoveUserData(	UInt32					/*inUserDataID*/,
1917 											UInt32					/*inIndex*/)
1918 {
1919 	return kAudioFileOperationNotSupportedError;
1920 }
1921 
MoveData(SInt64 fromPos,SInt64 toPos,SInt64 size)1922 OSStatus AudioFileObject::MoveData(SInt64 fromPos, SInt64 toPos, SInt64 size)
1923 {
1924 	if (fromPos == toPos)
1925 		return noErr;
1926 
1927 	OSStatus err = noErr;
1928 	CAAutoFree<char> audioData(kCopySoundDataBufferSize, true);
1929 
1930 	SInt64 bytesRemaining = size;
1931 	if (fromPos < toPos) {
1932 		while (bytesRemaining > 0)
1933 		{
1934 			// read from old file
1935 			UInt32 byteCount;
1936 			SInt64 count = (bytesRemaining < kCopySoundDataBufferSize) ? bytesRemaining : kCopySoundDataBufferSize;
1937 			err = GetDataSource()->ReadBytes(SEEK_SET, fromPos+(bytesRemaining-count), (UInt32)count, audioData(), &byteCount);
1938 			FailIf (err != noErr, Bail, "MoveData ReadBytes failed");
1939 
1940 			err = GetDataSource()->WriteBytes(SEEK_SET, toPos+(bytesRemaining-count), (UInt32)count, audioData(), &byteCount);
1941 			FailIf (err != noErr, Bail, "WriteBytes failed");
1942 
1943 			bytesRemaining -= count;
1944 		}
1945 	} else {
1946 		while (bytesRemaining > 0)
1947 		{
1948 			// read from old file
1949 			UInt32 byteCount;
1950 			SInt64 count = (bytesRemaining < kCopySoundDataBufferSize) ? bytesRemaining : kCopySoundDataBufferSize;
1951 			err = GetDataSource()->ReadBytes(SEEK_SET, fromPos+(size - bytesRemaining), (UInt32)count, audioData(), &byteCount);
1952 			FailIf (err != noErr, Bail, "MoveData ReadBytes failed");
1953 
1954 			err = GetDataSource()->WriteBytes(SEEK_SET, toPos+(size - bytesRemaining), (UInt32)count, audioData(), &byteCount);
1955 			FailIf (err != noErr, Bail, "WriteBytes failed");
1956 
1957 			bytesRemaining -= count;
1958 		}
1959 	}
1960 
1961 Bail:
1962 	return err;
1963 }
1964 
1965 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1966 
1967