/*
 *
 * @APPLE_LICENSE_HEADER_START@
 *
 * Copyright (c) 1999-2001 Apple Computer, Inc.  All Rights Reserved. The
 * contents of this file constitute Original Code as defined in and are
 * subject to the Apple Public Source License Version 1.2 (the 'License').
 * You may not use this file except in compliance with the License.  Please
 * obtain a copy of the License at http://www.apple.com/publicsource and
 * read it before using this file.
 *
 * This Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.  Please
 * see the License for the specific language governing rights and
 * limitations under the License.
 *
 *
 * @APPLE_LICENSE_HEADER_END@
 *
 */
// $Id: QTAtom_stsc.cpp,v 1.9 2001/08/14 14:28:43 murata Exp $
//
// QTAtom_stsc:
//   The 'stsc' QTAtom class.


// -------------------------------------
// Includes
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifndef __Win32__
#include <sys/types.h>
#include <netinet/in.h>
#endif

#include "QTFile.h"

#include "QTAtom.h"
#include "QTAtom_stsc.h"
#include "OSMemory.h"


// -------------------------------------
// Constants
//
const int		stscPos_VersionFlags		=  0;
const int		stscPos_NumEntries			=  4;
const int		stscPos_SampleTable			=  8;



// -------------------------------------
// Macros
//
#define DEBUG_PRINT(s) if(fDebug) printf s
#define DEEP_DEBUG_PRINT(s) if(fDeepDebug) printf s



// -------------------------------------
// Class state cookie
//
QTAtom_stsc_SampleTableControlBlock::QTAtom_stsc_SampleTableControlBlock(void)
{
	Reset();
}

QTAtom_stsc_SampleTableControlBlock::~QTAtom_stsc_SampleTableControlBlock(void)
{
}

void QTAtom_stsc_SampleTableControlBlock::Reset(void)
{
	fCurEntry = 0;
	fCurSample = 1;
	fLastFirstChunk = 1;
	fLastSamplesPerChunk = 1;
	fLastSampleDescription = 0;
	
	fLastFirstChunk_GetChunkFirstLastSample = 1;
	fLastSamplesPerChunk_GetChunkFirstLastSample = 1;
	fLastTotalSamples_GetChunkFirstLastSample = 0;	
	fCurEntry_GetChunkFirstLastSample = 0;
	chunkNumber_GetChunkFirstLastSample = 0;
	firstSample_GetChunkFirstLastSample = 0;
	lastSample_GetChunkFirstLastSample = 0;


	fCurEntry_SampleToChunkInfo = 0;
	fCurSample_SampleToChunkInfo = 1;
	fLastFirstChunk_SampleToChunkInfo = 1;
	fLastSamplesPerChunk_SampleToChunkInfo = 1;
	fLastSampleDescription_SampleToChunkInfo = 0;
	
	fFirstSampleNumber_SampleToChunkInfo = 0;
	fFirstSamplesPerChunk_SampleToChunkInfo = 0;
	fFirstChunkNumber_SampleToChunkInfo = 0;
	fFirstSampleDescriptionIndex_SampleToChunkInfo = 0;
	fFirstSampleOffsetInChunk_SampleToChunkInfo = 0;
	
	fGetSampleInfo_SampleNumber = 0;
	fGetSampleInfo_Length = 0;
	fGetSampleInfo_SampleDescriptionIndex = 0;
	fGetSampleInfo_Offset = 0;
	fGetSampleInfo_LastChunk = 0;
	fGetSampleInfo_LastChunkOffset = 0;
	
	fGetSizeOfSamplesInChunk_chunkNumber = 0;
	fGetSizeOfSamplesInChunk_firstSample = 0;
	fGetSizeOfSamplesInChunk_lastSample = 0;
	fGetSizeOfSamplesInChunk_size = 0;
	

}



// -------------------------------------
// Constructors and destructors
//
QTAtom_stsc::QTAtom_stsc(QTFile * File, QTFile::AtomTOCEntry * TOCEntry, Bool16 Debug, Bool16 DeepDebug)
	: QTAtom(File, TOCEntry, Debug, DeepDebug),
	  fNumEntries(0), fSampleToChunkTable(NULL)
{
}

QTAtom_stsc::~QTAtom_stsc(void)
{
	//
	// Free our variables.
	if( fSampleToChunkTable != NULL )
		delete[] fSampleToChunkTable;
}



// -------------------------------------
// Initialization functions
//
Bool16 QTAtom_stsc::Initialize(void)
{
	// Temporary vars
	UInt32		tempInt32;


	//
	// Parse this atom's fields.
	ReadInt32(stscPos_VersionFlags, &tempInt32);
	fVersion = (UInt8)((tempInt32 >> 24) & 0x000000ff);
	fFlags = tempInt32 & 0x00ffffff;

	ReadInt32(stscPos_NumEntries, &fNumEntries);

	//
	// Validate the size of the sample table.
	if( (unsigned long)(fNumEntries * 12) != (fTOCEntry.AtomDataLength - 8) )
		return false;

	//
	// Read in the sample-to-chunk table.
	fSampleToChunkTable = NEW char[fNumEntries * 12];
	if( fSampleToChunkTable == NULL )
		return false;
	
	ReadBytes(stscPos_SampleTable, fSampleToChunkTable, fNumEntries * 12);

	//
	// This atom has been successfully read in.
	return true;
}



// -------------------------------------
// Accessors
//

Bool16 QTAtom_stsc::GetChunkFirstLastSample(UInt32 chunkNumber, UInt32 *firstSample, UInt32 *lastSample,  QTAtom_stsc_SampleTableControlBlock *STCB)
{
	// Temporary state var
	QTAtom_stsc_SampleTableControlBlock	*tempSTCB = NULL;
	

	// General vars
	UInt32		prevFirstChunk = 0, thisFirstChunk = 0;
	UInt32		totalSamples = 0;
	UInt32 		numChunks = 0;
	UInt32 		numSamplesInChunks = 0;
	UInt32      prevSamplesPerChunk = 0;
	UInt32      samplesPerChunk = 0;
	
//	printf("GetChunkFirstLastSample chunk = %d STCB->chunkNumber_GetChunkFirstLastSample= %d \n",chunkNumber,STCB->chunkNumber_GetChunkFirstLastSample);
	 

	if( STCB == NULL )
	{
//		printf(" QTAtom_stsc::GetChunkFirstLastSample (NULL == STCB) \n");
		tempSTCB = NEW QTAtom_stsc_SampleTableControlBlock;
		STCB = tempSTCB;

	}	 
		
	if ( (STCB->chunkNumber_GetChunkFirstLastSample == chunkNumber) && (STCB->lastSample_GetChunkFirstLastSample > 0) )
	{
//		printf("GetChunkFirstLastSample cache hit chunk = %d\n",chunkNumber);
		if (firstSample) *firstSample = STCB->firstSample_GetChunkFirstLastSample;
		if (lastSample) *lastSample = STCB->lastSample_GetChunkFirstLastSample;
		goto GetChunkFirstLastSample_Done;
		
	}

	if (STCB->fCurEntry_GetChunkFirstLastSample > chunkNumber)
	{
//		printf(" QTAtom_stsc::GetChunkFirstLastSample missed Cache Loop \n");
		STCB->fLastFirstChunk_GetChunkFirstLastSample = 1;
		STCB->fLastSamplesPerChunk_GetChunkFirstLastSample = 1;
		STCB->fLastTotalSamples_GetChunkFirstLastSample = 0;	
		STCB->fCurEntry_GetChunkFirstLastSample = 0;
		STCB->chunkNumber_GetChunkFirstLastSample = 0;
		STCB->firstSample_GetChunkFirstLastSample = 0;
		STCB->lastSample_GetChunkFirstLastSample = 0;
	}	
	 
	if (STCB->fCurEntry_GetChunkFirstLastSample > 0)
	{
//		printf("GetChunkFirstLastSample cached loop chunk start = %d look for chunk = %ld\n",STCB->fLastFirstChunk_GetChunkFirstLastSample,chunkNumber);
		samplesPerChunk = STCB->fLastSamplesPerChunk_GetChunkFirstLastSample;
		totalSamples = STCB->fLastTotalSamples_GetChunkFirstLastSample;
		thisFirstChunk = STCB->fLastFirstChunk_GetChunkFirstLastSample;
	}

	
	//
	// Linearly search through the sample table until we find the chunk
	// which contains the given sample.
	
	if (fNumEntries == 1)
	{	
		memcpy(&samplesPerChunk, fSampleToChunkTable + (STCB->fCurEntry_GetChunkFirstLastSample * 12) + 4, 4);
		samplesPerChunk = ntohl(samplesPerChunk);
	
		prevSamplesPerChunk = ((chunkNumber -1 ) * samplesPerChunk);
		totalSamples = chunkNumber * samplesPerChunk;
	}
	else
	for( ; STCB->fCurEntry_GetChunkFirstLastSample < fNumEntries; STCB->fCurEntry_GetChunkFirstLastSample++ ) 
	{
		// Copy this entry's fields.
		prevSamplesPerChunk = samplesPerChunk;
		prevFirstChunk = thisFirstChunk;

		memcpy(&thisFirstChunk, fSampleToChunkTable + (STCB->fCurEntry_GetChunkFirstLastSample * 12) + 0, 4);
		thisFirstChunk = ntohl(thisFirstChunk);
		memcpy(&samplesPerChunk, fSampleToChunkTable + (STCB->fCurEntry_GetChunkFirstLastSample * 12) + 4, 4);
		samplesPerChunk = ntohl(samplesPerChunk);
		
		if (prevSamplesPerChunk == 0)  
			prevSamplesPerChunk = samplesPerChunk;
		
		if ( chunkNumber < thisFirstChunk ) // found chunk in group
		{	
//			printf("found chunk in group numEntries = %ld this chunk = %ld \n",fNumEntries, chunkNumber);
			numSamplesInChunks = (chunkNumber - prevFirstChunk) * prevSamplesPerChunk;
			totalSamples += numSamplesInChunks;
			prevSamplesPerChunk = totalSamples - prevSamplesPerChunk;
			break;
		}
		
		if ( chunkNumber == thisFirstChunk ) // found chunk 
		{
			numSamplesInChunks = samplesPerChunk;
			totalSamples += numSamplesInChunks;
			prevSamplesPerChunk = totalSamples - samplesPerChunk;
			break;
		}
		
		 
		numChunks = chunkNumber - prevFirstChunk;
		numSamplesInChunks = numChunks * samplesPerChunk;
		totalSamples += numSamplesInChunks;

		//
		// We have yet to find the sample; update our CurSample counter
		// and move on.
		STCB->fLastFirstChunk_GetChunkFirstLastSample = thisFirstChunk;
		STCB->fLastSamplesPerChunk_GetChunkFirstLastSample = samplesPerChunk;
		STCB->fLastTotalSamples_GetChunkFirstLastSample = totalSamples;

	}
	
	if (firstSample) *firstSample = prevSamplesPerChunk + 1;
	if (lastSample) *lastSample = totalSamples;
	
//	printf("Get Chunk %ld First %ld Last %ld prevSamplesPerChunk %ld samplesPerChunk %ld\n",chunkNumber,*firstSample,*lastSample,prevSamplesPerChunk,samplesPerChunk);

	STCB->chunkNumber_GetChunkFirstLastSample = chunkNumber;
	STCB->firstSample_GetChunkFirstLastSample =  prevSamplesPerChunk + 1;
	STCB->lastSample_GetChunkFirstLastSample = totalSamples;
	
GetChunkFirstLastSample_Done:
	delete tempSTCB;
	return true;
}


UInt32 QTAtom_stsc::GetChunkFirstSample(UInt32 chunkNumber)
{
	// Temporary state var
	QTAtom_stsc_SampleTableControlBlock	localSTCB;
	QTAtom_stsc_SampleTableControlBlock	*STCB = &localSTCB;
	
	// General vars
	UInt32		prevFirstChunk = 0, thisFirstChunk = 0, sampleDescription = 0;
	UInt32		totalSamples = 1;
	UInt32 		numChunks = 0;
	UInt32 		numSamplesInChunks = 0;
	UInt32		thisChunk = 0;
	UInt32      prevSamplesPerChunk = 0;
	UInt32      samplesPerChunk = 0;
	
	
	//
	// Linearly search through the sample table until we find the chunk
	// which contains the given sample.
	for( ; STCB->fCurEntry < fNumEntries; STCB->fCurEntry++ ) 
	{
		// Copy this entry's fields.
		prevSamplesPerChunk = samplesPerChunk;
		prevFirstChunk = thisFirstChunk;

		memcpy(&thisFirstChunk, fSampleToChunkTable + (STCB->fCurEntry * 12) + 0, 4);
		thisFirstChunk = ntohl(thisFirstChunk);
		memcpy(&samplesPerChunk, fSampleToChunkTable + (STCB->fCurEntry * 12) + 4, 4);
		samplesPerChunk = ntohl(samplesPerChunk);
		memcpy(&sampleDescription, fSampleToChunkTable + (STCB->fCurEntry * 12) + 8, 4);
		sampleDescription = ntohl(sampleDescription);
		
		thisChunk = thisFirstChunk;
		numChunks = thisFirstChunk - prevFirstChunk;
		
		if ( chunkNumber <= thisFirstChunk ) // found chunk in group
		{
			numChunks = chunkNumber - prevFirstChunk;
			numSamplesInChunks = numChunks * prevSamplesPerChunk;
			totalSamples += numSamplesInChunks;
			break;
		}
		
		
		numChunks = thisFirstChunk - prevFirstChunk;
		numSamplesInChunks = numChunks * prevSamplesPerChunk;
		totalSamples += numSamplesInChunks;

		//
		// We have yet to find the sample; update our CurSample counter
		// and move on.
		STCB->fLastFirstChunk = thisFirstChunk;
		STCB->fLastSampleDescription = sampleDescription;
		STCB->fLastSamplesPerChunk = samplesPerChunk;
	}
	

	return totalSamples;
}


//UInt32 gstscCacheCount = 0;
//UInt32 gstscCallCount = 0;


Bool16 QTAtom_stsc::SampleToChunkInfo(UInt32 SampleNumber,  UInt32 *samplesPerChunk,  UInt32 *ChunkNumber, UInt32 *SampleDescriptionIndex, UInt32 *SampleOffsetInChunk, QTAtom_stsc_SampleTableControlBlock * STCB) 
{
	// Temporary state var
	QTAtom_stsc_SampleTableControlBlock	*tempSTCB = NULL;
	
	// General vars
	UInt32		NewCurSample;
	UInt32		FirstChunk = 0, SamplesPerChunk = 0, SampleDescription = 0;
	
	Bool16		missedCache = false;

	if (STCB == NULL ) 
	{
//		printf(" QTAtom_stsc::SampleToChunkInfo (NULL == STCB) \n");
		tempSTCB = NEW QTAtom_stsc_SampleTableControlBlock;
		STCB = tempSTCB;
	}
	
	
	UInt32	aChunkNumber = 0;
	UInt32	aSampleDescriptionIndex = 0;
	UInt32	aSampleOffsetInChunk = 0;
	UInt32	aSamplesPerChunk = 0;

/*
	gstscCallCount ++;
	if (gstscCallCount == 1000)
	{
		printf("QTAtom_stsc::SampleToChunkInfo #calls = %ld, cache hits = %ld \n",gstscCallCount, gstscCacheCount);
		gstscCacheCount = 0;
		gstscCallCount = 0;

	}
*/
	
	//
	// Use a temporary STCB if we weren't given one.  We cannot use a default
	// STCB as we would have no way to know when we are seeking around in the
	// movie.

//	printf("------ QTAtom_stsc::SampleToChunkInfo SampleNumber = %ld\n",SampleNumber);

	if (STCB->fFirstSampleNumber_SampleToChunkInfo == SampleNumber)
	{
//		printf("------ QTAtom_stsc::SampleToChunkInfo cache hit SampleNumber = %ld\n",SampleNumber);

//		gstscCacheCount ++;
		aChunkNumber = STCB->fFirstChunkNumber_SampleToChunkInfo;
		aSampleDescriptionIndex = STCB->fFirstSampleDescriptionIndex_SampleToChunkInfo;
		aSamplesPerChunk = STCB->fFirstSamplesPerChunk_SampleToChunkInfo;
		aSampleOffsetInChunk = STCB->fFirstSampleOffsetInChunk_SampleToChunkInfo;

		if( ChunkNumber != NULL )
			*ChunkNumber = aChunkNumber;
		if( SampleDescriptionIndex != NULL )
			*SampleDescriptionIndex = aSampleDescriptionIndex;
		if( SampleOffsetInChunk != NULL )
			*SampleOffsetInChunk = aSampleOffsetInChunk;
		if (NULL != samplesPerChunk) 
			 *samplesPerChunk = aSamplesPerChunk;

		goto done;
	}
//	printf("QTAtom_stsc::SampleToChunkInfo missed cache SampleNumber = %ld\n",SampleNumber);

	//
	// Assume that this sample came out of the last chunk.
	aChunkNumber = STCB->fLastFirstChunk_SampleToChunkInfo + ((SampleNumber - STCB->fCurSample_SampleToChunkInfo) / STCB->fLastSamplesPerChunk_SampleToChunkInfo) ;
	aSampleDescriptionIndex = STCB->fLastSampleDescription_SampleToChunkInfo;
	aSampleOffsetInChunk = SampleNumber - (STCB->fCurSample_SampleToChunkInfo + ((aChunkNumber - STCB->fLastFirstChunk_SampleToChunkInfo) * STCB->fLastSamplesPerChunk_SampleToChunkInfo));
	aSamplesPerChunk = STCB->fLastSamplesPerChunk_SampleToChunkInfo;
	
	if( ChunkNumber != NULL )
		*ChunkNumber = aChunkNumber;
	if( SampleDescriptionIndex != NULL )
		*SampleDescriptionIndex = aSampleDescriptionIndex;
	if( SampleOffsetInChunk != NULL )
		*SampleOffsetInChunk = aSampleOffsetInChunk;
	if (NULL != samplesPerChunk) 
		 *samplesPerChunk = aSamplesPerChunk;
		 
	//
	// Linear search through the sample table until we find the chunk
	// which contains the given sample.

	if (STCB->fCurSample_SampleToChunkInfo > SampleNumber) // we missed the cache start over
	{	
		missedCache = true;
//		printf("missed loop Cache!! STCB = %ld STCB->fCurSample_SampleToChunkInfo = %ld  > SampleNumber = %ld \n",STCB, STCB->fCurSample_SampleToChunkInfo, SampleNumber);
		STCB->fCurEntry_SampleToChunkInfo = 0;
		STCB->fCurSample_SampleToChunkInfo = 1;
		STCB->fLastFirstChunk_SampleToChunkInfo = 1;
		STCB->fLastSamplesPerChunk_SampleToChunkInfo = 1;
		STCB->fLastSampleDescription_SampleToChunkInfo = 0;
	}



	for(; STCB->fCurEntry_SampleToChunkInfo < fNumEntries; STCB->fCurEntry_SampleToChunkInfo++ ) {
		//
		// Copy this entry's fields.
		memcpy(&FirstChunk, fSampleToChunkTable + (STCB->fCurEntry_SampleToChunkInfo * 12) + 0, 4);
		FirstChunk = ntohl(FirstChunk);
		memcpy(&SamplesPerChunk, fSampleToChunkTable + (STCB->fCurEntry_SampleToChunkInfo * 12) + 4, 4);
		SamplesPerChunk = ntohl(SamplesPerChunk);
		memcpy(&SampleDescription, fSampleToChunkTable + (STCB->fCurEntry_SampleToChunkInfo * 12) + 8, 4);
		SampleDescription = ntohl(SampleDescription);
		
		//
		// Check to see if the sample was actually in the last chunk and
		// return if it was.
		NewCurSample = STCB->fCurSample_SampleToChunkInfo +  (FirstChunk - STCB->fLastFirstChunk_SampleToChunkInfo) * STCB->fLastSamplesPerChunk_SampleToChunkInfo ;
		if( SampleNumber < NewCurSample )
		{
	
			if( ChunkNumber != NULL )
				*ChunkNumber = aChunkNumber;
			if( SampleDescriptionIndex != NULL )
				*SampleDescriptionIndex = aSampleDescriptionIndex;
			if( SampleOffsetInChunk != NULL )
				*SampleOffsetInChunk = aSampleOffsetInChunk;
			if (NULL != samplesPerChunk) 
				 *samplesPerChunk = aSamplesPerChunk;
		
			if (SampleNumber == 1 || missedCache)
			{
//					printf("QTAtom_stsc::SampleToChunkInfo (SampleNumber == %ld) \n",SampleNumber);
					STCB->fFirstChunkNumber_SampleToChunkInfo = aChunkNumber;
					STCB->fFirstSampleDescriptionIndex_SampleToChunkInfo = aSampleDescriptionIndex;
					STCB->fFirstSamplesPerChunk_SampleToChunkInfo = aSamplesPerChunk;
					STCB->fFirstSampleOffsetInChunk_SampleToChunkInfo = aSampleOffsetInChunk;
					STCB->fFirstSampleNumber_SampleToChunkInfo = SampleNumber;
			}
//			printf("GetSample Info in for loop returning offset %ld \n",aSampleOffsetInChunk);
			goto done;
		}	

		STCB->fCurSample_SampleToChunkInfo = NewCurSample;
		
		//
		// Assume that the sample will be in this chunk.
		

		aChunkNumber = FirstChunk + ((SampleNumber - STCB->fCurSample_SampleToChunkInfo) / SamplesPerChunk) ;
		aSampleDescriptionIndex = SampleDescription;
		aSampleOffsetInChunk = SampleNumber - (STCB->fCurSample_SampleToChunkInfo + ((aChunkNumber - FirstChunk) * SamplesPerChunk));
		aSamplesPerChunk = SamplesPerChunk;  
		
		//
		// We have yet to find the sample; update our CurSample counter
		// and move on.
		

		STCB->fLastFirstChunk_SampleToChunkInfo = FirstChunk;
		STCB->fLastSampleDescription_SampleToChunkInfo = SampleDescription;
		STCB->fLastSamplesPerChunk_SampleToChunkInfo = SamplesPerChunk;


	}

//	printf("GetSample Info fall out of loop returning offset%ld \n",aSampleOffsetInChunk);
	//
	// Falling out of the loop means that the sample is in the last chunk of
	// the table.
	
	if( ChunkNumber != NULL )
		*ChunkNumber = aChunkNumber;
	if( SampleDescriptionIndex != NULL )
		*SampleDescriptionIndex = aSampleDescriptionIndex;
	if( SampleOffsetInChunk != NULL )
		*SampleOffsetInChunk = aSampleOffsetInChunk;
	if (NULL != samplesPerChunk) 
		 *samplesPerChunk = aSamplesPerChunk;

	if (SampleNumber == 1 || missedCache)
	{
		STCB->fFirstChunkNumber_SampleToChunkInfo = aChunkNumber;
		STCB->fFirstSampleDescriptionIndex_SampleToChunkInfo = aSampleDescriptionIndex;
		STCB->fFirstSamplesPerChunk_SampleToChunkInfo = aSamplesPerChunk;
		STCB->fFirstSampleOffsetInChunk_SampleToChunkInfo = aSampleOffsetInChunk;
		STCB->fFirstSampleNumber_SampleToChunkInfo = SampleNumber;
	}

	
done:
	delete tempSTCB;
	return true;
}



// -------------------------------------
// Debugging functions
//
void QTAtom_stsc::DumpAtom(void)
{
	DEBUG_PRINT(("QTAtom_stsc::DumpAtom - Dumping atom.\n"));
	DEBUG_PRINT(("QTAtom_stsc::DumpAtom - ..Number of STC entries: %ld\n", fNumEntries));
}

void QTAtom_stsc::DumpTable(void)
{
	// General vars
	UInt32		FirstChunk = 0, SamplesPerChunk = 0, SampleDescription = 0;


	//
	// Print out a header.
	printf("-- Sample-to-Chunk table -------------------------------------------------------\n");
	printf("\n");
	printf("  Sample Num   FirstChunk  Samples/Chunk  Sample Description\n");
	printf("  ----------   ----------  -------------  ------------------\n");
	
	//
	// Print the table.
	for( UInt32 CurEntry = 0; CurEntry < fNumEntries; CurEntry++ ) {
		//
		// Copy this entry's fields.
		memcpy(&FirstChunk, fSampleToChunkTable + (CurEntry * 12) + 0, 4);
		FirstChunk = ntohl(FirstChunk);
		memcpy(&SamplesPerChunk, fSampleToChunkTable + (CurEntry * 12) + 4, 4);
		SamplesPerChunk = ntohl(SamplesPerChunk);
		memcpy(&SampleDescription, fSampleToChunkTable + (CurEntry * 12) + 8, 4);
		SampleDescription = ntohl(SampleDescription);
		
		//
		// Print out a listing.
		printf("  %10lu : %10lu   %10lu        %10lu\n",
			   CurEntry+1, FirstChunk, SamplesPerChunk, SampleDescription);
	}
}
