381 lines
11 KiB
C++
381 lines
11 KiB
C++
/*
|
|
*
|
|
* @APPLE_LICENSE_HEADER_START@
|
|
*
|
|
* Copyright (c) 1999-2008 Apple Inc. All Rights Reserved.
|
|
*
|
|
* This file contains Original Code and/or Modifications of Original Code
|
|
* as defined in and that are subject to the Apple Public Source License
|
|
* Version 2.0 (the 'License'). You may not use this file except in
|
|
* compliance with the License. Please obtain a copy of the License at
|
|
* http://www.opensource.apple.com/apsl/ and read it before using this
|
|
* file.
|
|
*
|
|
* The 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@
|
|
*
|
|
*/
|
|
|
|
//
|
|
// QTAtom_dref:
|
|
// The 'dref' QTAtom class.
|
|
|
|
|
|
// -------------------------------------
|
|
// Includes
|
|
//
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include "SafeStdLib.h"
|
|
#include <string.h>
|
|
|
|
#ifndef __Win32__
|
|
#include <sys/types.h>
|
|
#include <netinet/in.h>
|
|
#endif
|
|
|
|
#include "QTFile.h"
|
|
|
|
#include "QTAtom.h"
|
|
#include "QTAtom_dref.h"
|
|
#include "OSMemory.h"
|
|
|
|
|
|
// -------------------------------------
|
|
// Macros
|
|
//
|
|
#define DEBUG_PRINT(s) if(fDebug) qtss_printf s
|
|
#define DEEP_DEBUG_PRINT(s) if(fDeepDebug) qtss_printf s
|
|
|
|
|
|
|
|
// -------------------------------------
|
|
// Constants
|
|
//
|
|
const int drefPos_VersionFlags = 0;
|
|
const int drefPos_NumRefs = 4;
|
|
const int drefPos_RefTable = 8;
|
|
|
|
const int drefRefPos_Size = 0;
|
|
const int drefRefPos_Type = 4;
|
|
const int drefRefPos_VersionFlags = 8;
|
|
const int drefRefPos_Data = 12;
|
|
|
|
|
|
|
|
// -------------------------------------
|
|
// Mac alias constants and typedefs
|
|
//
|
|
|
|
enum {
|
|
kEndMark =-1, /* -1 end of variable info */
|
|
kAbsPath = 2, /* 2 absolute path name */
|
|
kMaxMark = 10 /* End Marker */
|
|
};
|
|
|
|
typedef struct
|
|
{
|
|
short what; /* what kind of information */
|
|
short len; /* length of variable data */
|
|
char data[1]; /* actual data */
|
|
} varInfo;
|
|
|
|
typedef struct
|
|
{
|
|
char private1[130];
|
|
short nlvlFrom; /* # of levels from fromFile/toFile until a common */
|
|
short nlvlTo; /* ancestor directory is found */
|
|
char private2[16];
|
|
varInfo vdata[1]; /* variable length info */
|
|
} AliasRecordPriv;
|
|
|
|
|
|
// -------------------------------------
|
|
// Constructors and destructors
|
|
//
|
|
QTAtom_dref::QTAtom_dref(QTFile * File, QTFile::AtomTOCEntry * TOCEntry, Bool16 Debug, Bool16 DeepDebug)
|
|
: QTAtom(File, TOCEntry, Debug, DeepDebug),
|
|
fNumRefs(0), fRefs(NULL)
|
|
{
|
|
}
|
|
|
|
QTAtom_dref::~QTAtom_dref(void)
|
|
{
|
|
//+ 6.16.1999 rt fix memory leak
|
|
for( UInt32 curRef = 0; curRef < fNumRefs; curRef++ )
|
|
{
|
|
delete [] fRefs[curRef].Data;
|
|
delete fRefs[curRef].FCB;
|
|
}
|
|
//-end
|
|
|
|
//
|
|
// Free our variables.
|
|
delete[] fRefs;
|
|
}
|
|
|
|
|
|
|
|
// -------------------------------------
|
|
// Initialization functions
|
|
//
|
|
Bool16 QTAtom_dref::Initialize(void)
|
|
{
|
|
// Temporary vars
|
|
UInt32 tempInt32;
|
|
|
|
// General vars
|
|
UInt64 refPos;
|
|
|
|
|
|
//
|
|
// Parse this atom's fields.
|
|
ReadInt32(drefPos_VersionFlags, &tempInt32);
|
|
fVersion = (UInt8)((tempInt32 >> 24) & 0x000000ff);
|
|
fFlags = tempInt32 & 0x00ffffff;
|
|
|
|
ReadInt32(drefPos_NumRefs, &fNumRefs);
|
|
|
|
//
|
|
// Read in all of the refs.
|
|
if( fNumRefs > 0 ) {
|
|
//
|
|
// Allocate our ref table.
|
|
fRefs = NEW DataRefEntry[fNumRefs];
|
|
if( fRefs == NULL )
|
|
return false;
|
|
|
|
//
|
|
// Read them all in..
|
|
refPos = drefPos_RefTable;
|
|
for( UInt32 CurRef = 0; CurRef < fNumRefs; CurRef++ ) {
|
|
//
|
|
// Set up the entry.
|
|
fRefs[CurRef].Flags = 0x0;
|
|
fRefs[CurRef].ReferenceType = FOUR_CHARS_TO_INT('N', 'U', 'L', 'L'); // NULL
|
|
fRefs[CurRef].DataLength = 0;
|
|
fRefs[CurRef].Data = NULL;
|
|
|
|
fRefs[CurRef].IsEntryInitialized = false;
|
|
fRefs[CurRef].IsFileOpen = false;
|
|
fRefs[CurRef].FCB = NULL;
|
|
|
|
|
|
//
|
|
// Get the flags and type.
|
|
ReadInt32(refPos + drefRefPos_VersionFlags, &tempInt32);
|
|
fRefs[CurRef].Flags = tempInt32 & 0x00ffffff;
|
|
|
|
ReadInt32(refPos + drefRefPos_Type, &tempInt32);
|
|
fRefs[CurRef].ReferenceType = tempInt32;
|
|
|
|
//
|
|
// We're done if this is a self-referencing atom.
|
|
if( fRefs[CurRef].Flags & flagSelfRef ) {
|
|
fRefs[CurRef].IsEntryInitialized = true;
|
|
continue;
|
|
}
|
|
|
|
|
|
//
|
|
// Get all of the data.
|
|
ReadInt32(refPos + drefRefPos_Size, &tempInt32);
|
|
fRefs[CurRef].DataLength = tempInt32 - 12 /* skip the header */;
|
|
|
|
fRefs[CurRef].Data = NEW char[fRefs[CurRef].DataLength];
|
|
if( fRefs[CurRef].Data == NULL ) {
|
|
//
|
|
// De-initialize this entry.
|
|
fRefs[CurRef].DataLength = 0;
|
|
fRefs[CurRef].IsEntryInitialized = false;
|
|
} else {
|
|
//
|
|
// Read the entry data.
|
|
ReadBytes(refPos + drefRefPos_Data, fRefs[CurRef].Data, fRefs[CurRef].DataLength);
|
|
|
|
//
|
|
// Configure the rest of the entry.
|
|
fRefs[CurRef].FCB = NEW QTFile_FileControlBlock();
|
|
if( fRefs[CurRef].FCB == NULL )
|
|
fRefs[CurRef].IsEntryInitialized = false;
|
|
else
|
|
fRefs[CurRef].IsEntryInitialized = true;
|
|
fRefs[CurRef].IsFileOpen = false;
|
|
}
|
|
|
|
//
|
|
// Skip over this mini-atom.
|
|
refPos += fRefs[CurRef].DataLength + 12 /* account for the header */;
|
|
}
|
|
}
|
|
|
|
//
|
|
// This atom has been successfully read in.
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
// -------------------------------------
|
|
// Read functions.
|
|
//
|
|
Bool16 QTAtom_dref::Read(UInt32 RefID, UInt64 Offset, char * const Buffer, UInt32 Length, QTFile_FileControlBlock * FCB)
|
|
{
|
|
// General vars
|
|
DataRefEntry *Entry;
|
|
|
|
|
|
//
|
|
// Validate that this ref exists.
|
|
if( (RefID == 0) || (RefID > fNumRefs) )
|
|
return false;
|
|
|
|
// qtss_printf("QTAtom_dref::Read Offset = %qd, Length = %"_S32BITARG_" \n", Offset, Length);
|
|
//
|
|
// If this data reference is in the movie file itself, then we can forward
|
|
// the request directly to QTFile.
|
|
if( IsRefInThisFile(RefID) )
|
|
return fFile->Read(Offset, Buffer, Length, FCB);
|
|
|
|
|
|
//
|
|
// The ref is not in this file; see if we have already opened an FCB for
|
|
// the file and use that, otherwise we need to process the ref.
|
|
Entry = &fRefs[RefID - 1];
|
|
|
|
//
|
|
// Abort if the entry was not initialized.
|
|
if( !Entry->IsEntryInitialized )
|
|
return false;
|
|
|
|
//
|
|
// Open the file (after parsing the data reference) if it is not open
|
|
// already.
|
|
if( !Entry->IsFileOpen ) {
|
|
// General vars
|
|
char *AliasPath;
|
|
|
|
|
|
//
|
|
// We only support parsing alias types.
|
|
if( Entry->ReferenceType != FOUR_CHARS_TO_INT('a', 'l', 'i', 's') ) //alis
|
|
return false;
|
|
|
|
//
|
|
// Parse the alias.
|
|
if( (AliasPath = ResolveAlias(Entry->Data, Entry->DataLength)) == NULL )
|
|
return false;
|
|
|
|
//
|
|
// Create a path which does *not* contain the current movie's name.
|
|
char * p;
|
|
char * MoviePath = fFile->GetMoviePath();
|
|
char * NewPath = NEW char[strlen(MoviePath) + strlen(AliasPath) + 1];
|
|
//char * NewPath = (char *)calloc(1, strlen(MoviePath) + strlen(AliasPath));
|
|
if( (p = strrchr(MoviePath, QT_PATH_SEPARATOR)) == NULL ) {
|
|
memcpy(NewPath, AliasPath, strlen(AliasPath) + 1);
|
|
} else {
|
|
int MoviePathClippedLength = (p - MoviePath) + 1;
|
|
memcpy(NewPath, MoviePath, MoviePathClippedLength);
|
|
memcpy(NewPath + MoviePathClippedLength, AliasPath, strlen(AliasPath) + 1);
|
|
}
|
|
|
|
|
|
//
|
|
// Do the open.
|
|
Entry->FCB->Set(NewPath);
|
|
if(!Entry->FCB->IsValid()) {
|
|
delete [] NewPath;
|
|
//free(NewPath);
|
|
return false;
|
|
}
|
|
|
|
Entry->IsFileOpen = true;
|
|
delete [] NewPath;
|
|
//free(NewPath);
|
|
}
|
|
|
|
//
|
|
// Do the read.
|
|
return fFile->Read(Offset, Buffer, Length, Entry->FCB);
|
|
}
|
|
|
|
|
|
|
|
// -------------------------------------
|
|
// Debugging functions
|
|
//
|
|
void QTAtom_dref::DumpAtom(void)
|
|
{
|
|
DEBUG_PRINT(("QTAtom_dref::DumpAtom - Dumping atom.\n"));
|
|
for( UInt32 CurRef = 1; CurRef <= fNumRefs; CurRef++ )
|
|
DEBUG_PRINT(("QTAtom_dref::DumpAtom - ..Ref #%"_U32BITARG_" is in file: %s\n", CurRef, IsRefInThisFile(CurRef) ? "yes" : "no"));
|
|
}
|
|
|
|
|
|
|
|
// -------------------------------------
|
|
// Protected member functions.
|
|
//
|
|
char * QTAtom_dref::ResolveAlias(char * const AliasData, UInt32 /* AliasDataLength */)
|
|
{
|
|
// General vars
|
|
AliasRecordPriv *Alias = (AliasRecordPriv *)AliasData;
|
|
varInfo *AliasVarInfo;
|
|
|
|
char *path, *pathStart;
|
|
int pathLength;
|
|
|
|
|
|
//
|
|
// Verify that we have a relative path.
|
|
if( (Alias->nlvlTo == -1) || (Alias->nlvlFrom == -1) )
|
|
return NULL;
|
|
|
|
//
|
|
// Search for the absolute pathname in this alias.
|
|
AliasVarInfo = Alias->vdata;
|
|
for( int loopCount = kMaxMark - 1; loopCount >= 0; loopCount--) {
|
|
//
|
|
// Break out of the loop if this is a match/the end of the alias.
|
|
if( ((short)ntohs(AliasVarInfo->what) == kAbsPath) || ((short)ntohs(AliasVarInfo->what) == kEndMark) )
|
|
break;
|
|
|
|
//
|
|
// Otherwise we need to move to the next data unit.
|
|
AliasVarInfo = (varInfo *)((char *)AliasVarInfo + ((ntohs(AliasVarInfo->len) + 1) & ~1) + 4 /* header size */);
|
|
}
|
|
|
|
|
|
//
|
|
// Now that we have the path, we need to strip off the absolute portions
|
|
// of it so that we can get at it from our current (relative) root.
|
|
AliasVarInfo->data[ntohs(AliasVarInfo->len)] = '\0';
|
|
|
|
pathStart = path = AliasVarInfo->data;
|
|
path += ntohs(AliasVarInfo->len);
|
|
int i = ntohs(Alias->nlvlTo);
|
|
pathLength = -1;
|
|
while( i && (path > pathStart) ) {
|
|
if( *path-- == ':' )
|
|
i--;
|
|
pathLength++;
|
|
}
|
|
|
|
if( i == 1 )
|
|
pathLength += 2; // fell out of loop; we're relative to root
|
|
else
|
|
path += 2; // points past separator character
|
|
|
|
|
|
//
|
|
// Return the alias.
|
|
return path;
|
|
}
|