Example #1
0
/*
 * Find an existing thread somewhere in the archive.  If the "copy" set
 * exists it will be searched.  If not, the "orig" set is searched, and
 * if an entry is found a "copy" set will be created.
 *
 * The record and thread returned will always be from the "copy" set.  An
 * error result is returned if the record and thread aren't found.
 */
static NuError Nu_FindThreadForWriteByIdx(NuArchive* pArchive,
    NuThreadIdx threadIdx, NuRecord** ppFoundRecord, NuThread** ppFoundThread)
{
    NuError err;

    if (Nu_RecordSet_GetLoaded(&pArchive->copyRecordSet)) {
        err = Nu_RecordSet_FindByThreadIdx(&pArchive->copyRecordSet, threadIdx,
                ppFoundRecord, ppFoundThread);
    } else {
        Assert(Nu_RecordSet_GetLoaded(&pArchive->origRecordSet));
        err = Nu_RecordSet_FindByThreadIdx(&pArchive->origRecordSet, threadIdx,
                ppFoundRecord, ppFoundThread);
        *ppFoundThread = NULL;       /* can't delete from here, wipe ptr */
    }
    BailError(err);

    /*
     * The thread exists.  If we were looking in the "orig" set, we have
     * to create a "copy" set, and delete it from that.
     */
    if (*ppFoundThread == NULL) {
        err = Nu_RecordSet_Clone(pArchive, &pArchive->copyRecordSet,
                &pArchive->origRecordSet);
        BailError(err);
        err = Nu_RecordSet_FindByThreadIdx(&pArchive->copyRecordSet, threadIdx,
                ppFoundRecord, ppFoundThread);
        Assert(err == kNuErrNone && *ppFoundThread != NULL); /* must succeed */
        BailError(err);
    }

bail:
    return err;
}
PicHandle QTEffects_GetPosterPictFromFirstVideoTrackInMovieFile (FSSpec *theSpec)
{
	PicHandle	myPict = NULL;
	Movie		myMovie = NULL;
	Track		myTrack = NULL;
	short		myRefNum = 0;
	OSErr		myErr = noErr;
	
	myErr = OpenMovieFile(theSpec, &myRefNum, fsRdPerm);
	BailError(myErr);

	myErr = NewMovieFromFile(&myMovie, myRefNum, NULL, NULL, 0, NULL);
	BailError(myErr);
	
	SetMoviePlayHints(myMovie, hintsHighQuality, hintsHighQuality);

	myErr = CloseMovieFile(myRefNum);
	BailError(myErr);
	
	myErr = QTEffects_GetFirstVideoTrackInMovie(myMovie, &myTrack);
	BailNil(myTrack);
	
	myPict = GetTrackPict(myTrack, GetMoviePosterTime(myMovie));

bail:
	if (myMovie != NULL)
		DisposeMovie(myMovie);
	
	return(myPict);
}
Example #3
0
/*
 * Extract a thread, given the IDs and a data sink.
 */
NuError Nu_ExtractThread(NuArchive* pArchive, NuThreadIdx threadIdx,
    NuDataSink* pDataSink)
{
    NuError err;
    NuRecord* pRecord;
    NuThread* pThread;

    if (Nu_IsStreaming(pArchive))
        return kNuErrUsage;
    if (threadIdx == 0 || pDataSink == NULL)
        return kNuErrInvalidArg;
    err = Nu_GetTOCIfNeeded(pArchive);
    BailError(err);

    /* find the correct record and thread by index */
    err = Nu_RecordSet_FindByThreadIdx(&pArchive->origRecordSet, threadIdx,
            &pRecord, &pThread);
    BailError(err);
    Assert(pRecord != NULL);

    /* extract away */
    err = Nu_ExtractThreadCommon(pArchive, pRecord, pThread, pDataSink);
    BailError(err);

bail:
    return err;
}
Example #4
0
/*
 * Determine if it's okay to add a thread of the type specified by
 * "threadID" into "pRecord".
 *
 * Returns with an error (kNuErrThreadAdd) if it's not okay.
 */
NuError Nu_OkayToAddThread(NuArchive* pArchive, const NuRecord* pRecord,
    NuThreadID threadID)
{
    NuError err = kNuErrNone;

    /*
     * Check for class conflicts (can't mix data and control threads).
     */
    if (NuThreadIDGetClass(threadID) == kNuThreadClassData) {
        err = Nu_FindNoFutureThreadClass(pArchive, pRecord,
                kNuThreadClassControl);
        BailError(err);
    } else if (NuThreadIDGetClass(threadID) == kNuThreadClassControl) {
        err = Nu_FindNoFutureThreadClass(pArchive, pRecord,
                kNuThreadClassData);
        BailError(err);
    }

    /*
     * Check for specific type conflicts.
     */
    if (threadID == kNuThreadIDDataFork) {
        err = Nu_FindNoFutureThread(pArchive, pRecord, kNuThreadIDDataFork);
        BailError(err);
        err = Nu_FindNoFutureThread(pArchive, pRecord, kNuThreadIDDiskImage);
        BailError(err);
    } else if (threadID == kNuThreadIDRsrcFork) {
        err = Nu_FindNoFutureThread(pArchive, pRecord, kNuThreadIDRsrcFork);
        BailError(err);
        err = Nu_FindNoFutureThread(pArchive, pRecord, kNuThreadIDDiskImage);
        BailError(err);
    } else if (threadID == kNuThreadIDDiskImage) {
        err = Nu_FindNoFutureThread(pArchive, pRecord, kNuThreadIDDataFork);
        BailError(err);
        err = Nu_FindNoFutureThread(pArchive, pRecord, kNuThreadIDRsrcFork);
        BailError(err);
        err = Nu_FindNoFutureThread(pArchive, pRecord, kNuThreadIDDiskImage);
        BailError(err);
    } else if (threadID == kNuThreadIDFilename) {
        err = Nu_FindNoFutureThread(pArchive, pRecord, kNuThreadIDFilename);
        BailError(err);
    }

bail:
    return err;
}
Example #5
0
/*
 * Delete an individual thread.
 *
 * You aren't allowed to delete threads that have been updated.  Deleting
 * newly-added threads isn't possible, since they aren't really threads yet.
 *
 * Don't worry about deleting filename threads here; we take care of that
 * later on.  Besides, it's sort of handy to hang on to the filename for
 * as long as possible.
 */
NuError Nu_DeleteThread(NuArchive* pArchive, NuThreadIdx threadIdx)
{
    NuError err;
    NuThreadMod* pThreadMod = NULL;
    NuRecord* pFoundRecord;
    NuThread* pFoundThread;

    if (Nu_IsReadOnly(pArchive))
        return kNuErrArchiveRO;
    err = Nu_GetTOCIfNeeded(pArchive);
    BailError(err);

    /*
     * Find the thread in the "copy" set.  (If there isn't a copy set,
     * make one.)
     */
    err = Nu_FindThreadForWriteByIdx(pArchive, threadIdx, &pFoundRecord,
            &pFoundThread);
    BailError(err);

    /*
     * Deletion of modified threads (updates or previous deletes) isn't
     * allowed.  Deletion of threads from deleted records can't happen,
     * because deleted records are completely removed from the "copy" set.
     */
    if (Nu_ThreadMod_FindByThreadIdx(pFoundRecord, threadIdx) != NULL) {
        DBUG(("--- Tried to delete a deleted or modified thread\n"));
        err = kNuErrModThreadChange;
        goto bail;
    }

    /*
     * Looks good.  Add a new "delete" ThreadMod to the list.
     */
    err = Nu_ThreadModDelete_New(pArchive, threadIdx,
                NuGetThreadID(pFoundThread), &pThreadMod);
    BailError(err);
    Nu_RecordAddThreadMod(pFoundRecord, pThreadMod);
    pThreadMod = NULL;   /* successful, don't free */

bail:
    Nu_ThreadModFree(pArchive, pThreadMod);
    return err;
}
Example #6
0
/*
 * Extract a thread from the archive as part of a "bulk" extract operation.
 *
 * Streaming archives must be properly positioned.
 */
NuError Nu_ExtractThreadBulk(NuArchive* pArchive, const NuRecord* pRecord,
    const NuThread* pThread)
{
    NuError err;
    NuDataSink* pDataSink = NULL;
    UNICHAR* recFilenameStorageUNI = NULL;
    NuValue eolConv;

    /*
     * Create a file data sink for the file.  We use whatever EOL conversion
     * is set as the default for the entire archive.  (If you want to
     * specify your own EOL conversion for each individual file, you will
     * need to extract them individually, creating a data sink for each.)
     *
     * One exception: we turn EOL conversion off for disk image threads.
     * It's *very* unlikely this would be desirable, and could be a problem
     * if the user is extracting a collection of disks and files.
     */
    eolConv = pArchive->valConvertExtractedEOL;
    if (NuGetThreadID(pThread) == kNuThreadIDDiskImage)
        eolConv = kNuConvertOff;
    recFilenameStorageUNI = Nu_CopyMORToUNI(pRecord->filenameMOR);
    err = Nu_DataSinkFile_New(true, eolConv, recFilenameStorageUNI,
            NuGetSepFromSysInfo(pRecord->recFileSysInfo), &pDataSink);
    BailError(err);

    err = Nu_ExtractThreadCommon(pArchive, pRecord, pThread, pDataSink);
    BailError(err);

bail:
    if (pDataSink != NULL) {
        NuError err2 = Nu_DataSinkFree(pDataSink);
        if (err == kNuErrNone)
            err = err2;
    }
    Nu_Free(pArchive, recFilenameStorageUNI);

    return err;
}
Example #7
0
/*
 * Extract the thread to the specified file pointer.
 *
 * If the archive is a stream, the stream must be positioned at the
 * start of pThread's data.  If not, it will be seeked first.
 */
static NuError Nu_ExtractThreadToDataSink(NuArchive* pArchive,
    const NuRecord* pRecord, const NuThread* pThread,
    NuProgressData* pProgress, NuDataSink* pDataSink)
{
    NuError err;
    NuFunnel* pFunnel = NULL;

    /* if it's not a stream, seek to the appropriate spot in the file */
    if (!Nu_IsStreaming(pArchive)) {
        err = Nu_SeekArchive(pArchive, pArchive->archiveFp,
                pThread->fileOffset, SEEK_SET);
        if (err != kNuErrNone) {
            Nu_ReportError(NU_BLOB, err, "Unable to seek input to %ld",
                pThread->fileOffset);
            goto bail;
        }
    }

    /*
     * Set up an output funnel to write to.
     */
    err = Nu_FunnelNew(pArchive, pDataSink, Nu_DataSinkGetConvertEOL(pDataSink),
            pArchive->valEOL, pProgress, &pFunnel);
    BailError(err);

    /*
     * Write it.
     */
    err = Nu_ExpandStream(pArchive, pRecord, pThread, pArchive->archiveFp,
            pFunnel);
    if (err != kNuErrNone) {
        if (err != kNuErrSkipped && err != kNuErrAborted)
            Nu_ReportError(NU_BLOB, err, "ExpandStream failed");
        goto bail;
    }

bail:
    (void) Nu_FunnelFree(pArchive, pFunnel);
    return err;
}
Example #8
0
/*
 * Write the thread headers for the record at the current file position.
 *
 * Note this doesn't care whether a thread was "fake" or not.  In
 * effect, we promote all threads to "real" status.  We update the
 * "fake" count in pRecord accordingly.
 */
NuError Nu_WriteThreadHeaders(NuArchive* pArchive, NuRecord* pRecord, FILE* fp,
    uint16_t* pCrc)
{
    NuError err = kNuErrNone;
    NuThread* pThread;
    int idx;

    for (idx = 0; idx < (int)pRecord->recTotalThreads; idx++) {
        pThread = Nu_GetThread(pRecord, idx);
        Assert(pThread != NULL);

        err = Nu_WriteThreadHeader(pArchive, pThread, fp, pCrc);
        BailError(err);
    }

    if (pRecord->fakeThreads != 0) {
        DBUG(("+++ promoting %ld fake threads to real\n",pRecord->fakeThreads));
        pRecord->fakeThreads = 0;
    }

bail:
    return err;
}
Example #9
0
/*
 * Extract the specified thread to "pDataSink".  If the sink is to a file,
 * this will take care of opening (and, if appropriate, creating) the file.
 *
 * If we're operating on a streaming archive, the file pointer must be
 * positioned at the start of the thread's data.  If not, it will be
 * seeked appropriately.
 *
 * This calls the "should we extract" and "what pathname should we use"
 * filters for every thread, which means we can reject specific kinds
 * of forks and/or give them different names.  This is a good thing.
 */
static NuError Nu_ExtractThreadCommon(NuArchive* pArchive,
    const NuRecord* pRecord, const NuThread* pThread, NuDataSink* pDataSink)
{
    NuError err = kNuErrNone;
    NuSelectionProposal selProposal;
    NuPathnameProposal pathProposal;
    NuProgressData progressData;
    NuProgressData* pProgressData;
    NuDataSink* pOrigDataSink;
    UNICHAR* newPathStorageUNI = NULL;
    UNICHAR* recFilenameStorageUNI = NULL;
    const UNICHAR* newPathnameUNI;
    NuResult result;
    uint8_t newFssep;
    Boolean doFreeSink = false;

    Assert(pRecord != NULL);
    Assert(pThread != NULL);
    Assert(pDataSink != NULL);

    memset(&progressData, 0, sizeof(progressData));
    pProgressData = NULL;

    /*
     * If we're just trying to verify the archive contents, create a
     * data sink that goes nowhere at all.
     */
    if (pArchive->testMode) {
        err = Nu_DataSinkVoid_New(
                Nu_DataSinkGetDoExpand(pDataSink),
                Nu_DataSinkGetConvertEOL(pDataSink),
                &pDataSink);
        BailError(err);
        doFreeSink = true;
    }

    pOrigDataSink = pDataSink;  /* save a copy for the "retry" loop */

    /*
     * Decide if we want to extract this thread.  This is mostly for
     * use by the "bulk" extract, not the per-thread extract, but it
     * still applies if they so desire.
     */
    if (pArchive->selectionFilterFunc != NULL) {
        selProposal.pRecord = pRecord;
        selProposal.pThread = pThread;
        result = (*pArchive->selectionFilterFunc)(pArchive, &selProposal);

        if (result == kNuSkip)
            return Nu_SkipThread(pArchive, pRecord, pThread);
        if (result == kNuAbort) {
            err = kNuErrAborted;
            goto bail;
        }
    }

    newPathnameUNI = NULL;
    newFssep = 0;

    recFilenameStorageUNI = Nu_CopyMORToUNI(pRecord->filenameMOR);

retry_name:
    if (Nu_DataSinkGetType(pDataSink) == kNuDataSinkToFile) {
        /*
         * We're extracting.  Figure out the name of the file to write it to.
         * If they want to use the sleazy FILE* back door, create a new
         * data sink and use that instead.
         *
         * Start by resetting everything to defaults, in case this isn't
         * our first time through the "rename" loop.
         */
        newPathnameUNI = Nu_DataSinkFile_GetPathname(pDataSink);
        newFssep = Nu_DataSinkFile_GetFssep(pDataSink);
        pDataSink = pOrigDataSink;

        /* if they don't have a pathname func defined, we just use default */
        if (pArchive->outputPathnameFunc != NULL) {
            pathProposal.pathnameUNI = recFilenameStorageUNI;
            pathProposal.filenameSeparator =
                                NuGetSepFromSysInfo(pRecord->recFileSysInfo);
            pathProposal.pRecord = pRecord;
            pathProposal.pThread = pThread;
            pathProposal.newPathnameUNI = NULL;
            pathProposal.newFilenameSeparator = '\0';
            /*pathProposal.newStorage = (NuThreadID)-1;*/
            pathProposal.newDataSink = NULL;

            result = (*pArchive->outputPathnameFunc)(pArchive, &pathProposal);

            if (result == kNuSkip)
                return Nu_SkipThread(pArchive, pRecord, pThread);
            if (result == kNuAbort) {
                err = kNuErrAborted;
                goto bail;
            }

            /* we don't own this string, so make a copy */
            if (pathProposal.newPathnameUNI != NULL) {
                Nu_Free(pArchive, newPathStorageUNI);
                newPathStorageUNI = strdup(pathProposal.newPathnameUNI);
                newPathnameUNI = newPathStorageUNI;
            } else {
                newPathnameUNI = NULL;
            }
            if (pathProposal.newFilenameSeparator != '\0')
                newFssep = pathProposal.newFilenameSeparator;

            /* if they want to send this somewhere else, let them */
            if (pathProposal.newDataSink != NULL)
                pDataSink = pathProposal.newDataSink;
        }

        /* at least one of these must be set */
        Assert(!(newPathnameUNI == NULL && pathProposal.newDataSink == NULL));
    }

    /*
     * Prepare the progress data if this is a data thread.
     */
    if (newPathnameUNI == NULL) {
        /* using a data sink; get the pathname out of the record */
        newPathnameUNI = recFilenameStorageUNI;
        newFssep = NuGetSepFromSysInfo(pRecord->recFileSysInfo);
    }
    if (pThread->thThreadClass == kNuThreadClassData) {
        pProgressData = &progressData;
        err = Nu_ProgressDataInit_Expand(pArchive, pProgressData, pRecord,
                newPathnameUNI, newFssep, recFilenameStorageUNI,
                Nu_DataSinkGetConvertEOL(pOrigDataSink));
        BailError(err);

        /* send initial progress so they see the right name if "open" fails */
        pProgressData->state = kNuProgressOpening;
        err = Nu_SendInitialProgress(pArchive, pProgressData);
        BailError(err);
    }

    if (Nu_DataSinkGetType(pDataSink) == kNuDataSinkToFile) {
        /*
         * We're extracting to a file.  Open it, creating it if necessary and
         * allowed.
         */
        FILE* fileFp = NULL;

        err = Nu_OpenOutputFile(pArchive, pRecord, pThread, newPathnameUNI,
                newFssep, &fileFp);
        if (err == kNuErrRename) {
            /* they want to rename; the OutputPathname callback handles this */
            Nu_Free(pArchive, newPathStorageUNI);
            newPathStorageUNI = NULL;
            /* reset these just to be careful */
            newPathnameUNI = NULL;
            fileFp = NULL;
            goto retry_name;
        } else if (err != kNuErrNone) {
            goto bail;
        }

        Assert(fileFp != NULL);
        (void) Nu_DataSinkFile_SetFP(pDataSink, fileFp);

        DBUG(("+++ EXTRACTING 0x%08lx from '%s' at offset %0ld to '%s'\n",
            NuMakeThreadID(pThread->thThreadClass, pThread->thThreadKind),
            pRecord->filename, pThread->fileOffset, newPathname));
    } else {
        DBUG(("+++ EXTRACTING 0x%08lx from '%s' at offset %0ld to sink\n",
            NuMakeThreadID(pThread->thThreadClass, pThread->thThreadKind),
            pRecord->filename, pThread->fileOffset));
    }

    /* extract to the file */
    err = Nu_ExtractThreadToDataSink(pArchive, pRecord, pThread,
            pProgressData, pDataSink);
    BailError(err);

    if (Nu_DataSinkGetType(pDataSink) == kNuDataSinkToFile) {
        /*
         * Close the file, adjusting the modification date and access
         * permissions as appropriate.
         */
        err = Nu_CloseOutputFile(pArchive, pRecord,
                Nu_DataSinkFile_GetFP(pDataSink), newPathnameUNI);
        Nu_DataSinkFile_SetFP(pDataSink, NULL);
        BailError(err);
    }

bail:
    if (err != kNuErrNone && pProgressData != NULL) {
        /* send a final progress message, indicating failure */
        if (err == kNuErrSkipped)
            pProgressData->state = kNuProgressSkipped;
        else if (err == kNuErrAborted)
            pProgressData->state = kNuProgressAborted;
        else
            pProgressData->state = kNuProgressFailed;
        (void) Nu_SendInitialProgress(pArchive, pProgressData);
    }

    /* if this was an ordinary file, and it's still open, close it */
    if (Nu_DataSinkGetType(pDataSink) == kNuDataSinkToFile)
        Nu_DataSinkFile_Close(pDataSink);

    Nu_Free(pArchive, newPathStorageUNI);
    Nu_Free(pArchive, recFilenameStorageUNI);

    if (doFreeSink)
        Nu_DataSinkFree(pDataSink);
    return err;
}
Example #10
0
/*
 * Skip past some or all of the thread data in the archive.  For file
 * archives, we scan all the threads, but for streaming archives we only
 * want to scan up to the filename thread.  (If the filename thread comes
 * after one of the data threads, we have a problem!)
 *
 * The tricky part here is that we don't want to skip over a filename
 * thread.  We actually want to read it in, so that we have something to
 * show to the application.  (Someday I'll get AndyN for putting me
 * through this...)
 */
NuError Nu_ScanThreads(NuArchive* pArchive, NuRecord* pRecord, long numThreads)
{
    NuError err = kNuErrNone;
    NuThread* pThread;
    FILE* fp;

    Assert(pArchive != NULL);
    Assert(pRecord != NULL);

    fp = pArchive->archiveFp;

    Assert(numThreads <= (long)pRecord->recTotalThreads);

    pThread = pRecord->pThreads;
    while (numThreads--) {
        if (pRecord->threadFilenameMOR == NULL &&
            NuMakeThreadID(pThread->thThreadClass, pThread->thThreadKind) ==
                kNuThreadIDFilename)
        {
            /* it's the first filename thread, read the whole thing */
            if (pThread->thCompThreadEOF > kNuReasonableFilenameLen) {
                err = kNuErrBadRecord;
                Nu_ReportError(NU_BLOB, err, "Bad thread filename len (%u)",
                    pThread->thCompThreadEOF);
                goto bail;
            }
            pRecord->threadFilenameMOR = Nu_Malloc(pArchive,
                                        pThread->thCompThreadEOF +1);
            BailAlloc(pRecord->threadFilenameMOR);

            /* note there is no CRC on a filename thread */
            (void) Nu_ReadBytes(pArchive, fp, pRecord->threadFilenameMOR,
                    pThread->thCompThreadEOF);
            if ((err = Nu_HeaderIOFailed(pArchive, fp)) != kNuErrNone) {
                Nu_ReportError(NU_BLOB, err, "Failed reading filename thread");
                goto bail;
            }

            /* null-terminate on the actual len, not the buffer len */
            pRecord->threadFilenameMOR[pThread->thThreadEOF] = '\0';

            Nu_StripHiIfAllSet(pRecord->threadFilenameMOR);

            /* prefer this one over the record one, but only one should exist */
            if (pRecord->filenameMOR != NULL) {
                DBUG(("--- HEY: got record filename and thread filename\n"));
            }
            pRecord->filenameMOR = pRecord->threadFilenameMOR;

        } else {
            /* not a filename (or not first filename), skip past it */
            err = Nu_SeekArchive(pArchive, pArchive->archiveFp,
                    pThread->thCompThreadEOF, SEEK_CUR);
            BailError(err);
        }

        pThread++;
    }

    /*
     * Should've had one by now.  Supposedly, older versions of ShrinkIt
     * wouldn't prompt for a disk image name on DOS 3.3 volumes, so you'd
     * end up with a disk image that had no name attached.  This will tend
     * to confuse things, so we go ahead and give it a name.
     */
    if (pRecord->filenameMOR == NULL) {
        DBUG(("+++ no filename found, using default record name\n"));
        pRecord->filenameMOR = kNuDefaultRecordName;
    }

    pArchive->currentOffset += pRecord->totalCompLength;

    if (!Nu_IsStreaming(pArchive)) {
        Assert(pArchive->currentOffset == ftell(pArchive->archiveFp));
    }

bail:
    return err;
}
Example #11
0
/*
 * Read the threads from the current archive file position.
 *
 * The storage for the threads is allocated here, in one block.  We could
 * have used a linked list like NuLib, but that doesn't really provide any
 * benefit for us, and adds complexity.
 */
NuError Nu_ReadThreadHeaders(NuArchive* pArchive, NuRecord* pRecord,
    uint16_t* pCrc)
{
    NuError err = kNuErrNone;
    NuThread* pThread;
    long count;
    Boolean needFakeData, needFakeRsrc;

    needFakeData = true;
    needFakeRsrc = (pRecord->recStorageType == kNuStorageExtended);

    Assert(pArchive != NULL);
    Assert(pRecord != NULL);
    Assert(pCrc != NULL);

    if (!pRecord->recTotalThreads) {
        /* not sure if this is reasonable, but we can handle it */
        DBUG(("--- WEIRD: no threads in the record?\n"));
        goto bail;
    }

    pRecord->pThreads = Nu_Malloc(pArchive,
                            pRecord->recTotalThreads * sizeof(NuThread));
    BailAlloc(pRecord->pThreads);

    count = pRecord->recTotalThreads;
    pThread = pRecord->pThreads;
    while (count--) {
        err = Nu_ReadThreadHeader(pArchive, pThread, pCrc);
        BailError(err);

        if (pThread->thThreadClass == kNuThreadClassData) {
            if (pThread->thThreadKind == kNuThreadKindDataFork) {
                needFakeData = false;
            } else if (pThread->thThreadKind == kNuThreadKindRsrcFork) {
                needFakeRsrc = false;
            } else if (pThread->thThreadKind == kNuThreadKindDiskImage) {
                /* needFakeRsrc shouldn't be set, but clear anyway */
                needFakeData = needFakeRsrc = false;
            }
        }

        /*
         * Some versions of ShrinkIt write an invalid thThreadEOF for disks,
         * so we have to figure out what it's supposed to be.
         */
        if (NuMakeThreadID(pThread->thThreadClass, pThread->thThreadKind) ==
            kNuThreadIDDiskImage)
        {
            if (pRecord->recStorageType <= 13) {
                /* supposed to be block size, but SHK v3.0.1 stored it wrong */
                pThread->actualThreadEOF = pRecord->recExtraType * 512;

            } else if (pRecord->recStorageType == 256 &&
                       pRecord->recExtraType == 280 &&
                       pRecord->recFileSysID == kNuFileSysDOS33)
            {
                /*
                 * Fix for less-common ShrinkIt problem: looks like an old
                 * version of GS/ShrinkIt used 256 as the block size when
                 * compressing DOS 3.3 images from 5.25" disks.  If that
                 * appears to be the case here, crank up the block size.
                 */
                DBUG(("--- no such thing as a 70K disk image!\n"));
                pThread->actualThreadEOF = pRecord->recExtraType * 512;

            } else {
                pThread->actualThreadEOF =
                    pRecord->recExtraType * pRecord->recStorageType;
            }
        } else {
            pThread->actualThreadEOF = pThread->thThreadEOF;
        }

        pThread->used = false;
        pThread++;
    }

    /*
     * If "mask threadless" is set, create "fake" threads with empty
     * data and resource forks as needed.
     */
    if ((needFakeData || needFakeRsrc) && pArchive->valMaskDataless) {
        int firstNewThread = pRecord->recTotalThreads;

        if (needFakeData) {
            pRecord->recTotalThreads++;
            pRecord->fakeThreads++;
        }
        if (needFakeRsrc) {
            pRecord->recTotalThreads++;
            pRecord->fakeThreads++;
        }

        pRecord->pThreads = Nu_Realloc(pArchive, pRecord->pThreads,
                                pRecord->recTotalThreads * sizeof(NuThread));
        BailAlloc(pRecord->pThreads);

        pThread = pRecord->pThreads + firstNewThread;

        if (needFakeData) {
            pThread->thThreadClass = kNuThreadClassData;
            pThread->thThreadFormat = kNuThreadFormatUncompressed;
            pThread->thThreadKind = kNuThreadKindDataFork;
            pThread->thThreadCRC = kNuInitialThreadCRC;
            pThread->thThreadEOF = 0;
            pThread->thCompThreadEOF = 0;
            pThread->threadIdx = Nu_GetNextThreadIdx(pArchive);
            pThread->actualThreadEOF = 0;
            pThread->fileOffset = -99999999;
            pThread->used = false;
            pThread++;
        }
        if (needFakeRsrc) {
            pThread->thThreadClass = kNuThreadClassData;
            pThread->thThreadFormat = kNuThreadFormatUncompressed;
            pThread->thThreadKind = kNuThreadKindRsrcFork;
            pThread->thThreadCRC = kNuInitialThreadCRC;
            pThread->thThreadEOF = 0;
            pThread->thCompThreadEOF = 0;
            pThread->threadIdx = Nu_GetNextThreadIdx(pArchive);
            pThread->actualThreadEOF = 0;
            pThread->fileOffset = -99999999;
            pThread->used = false;
        }
    }

bail:
    return err;
}
Example #12
0
/*
 * Open the archive in read-write mode, for purposes of adding, deleting,
 * or updating files.  We don't plan on extracting anything with this.
 *
 * "Streaming mode" isn't allowed.
 */
NuError OpenArchiveReadWrite(NulibState* pState)
{
    NuError err = kNuErrNone;
    NuArchive* pArchive = NULL;
    char* tempName = NULL;

    Assert(pState != NULL);
    Assert(IsFilenameStdin(NState_GetArchiveFilename(pState)) == false);

    tempName = MakeTempArchiveName(pState);
    if (tempName == NULL)
        goto bail;
    DBUG(("TEMP NAME = '%s'\n", tempName));

    err = NuOpenRW(NState_GetArchiveFilename(pState), tempName,
            kNuOpenCreat, &pArchive);
    if (err != kNuErrNone) {
        ReportError(err, "unable to open '%s'",
            NState_GetArchiveFilename(pState));
        goto bail;
    }

    /* introduce them */
    NState_SetNuArchive(pState, pArchive);
    err = NuSetExtraData(pArchive, pState);
    BailError(err);

    NuSetSelectionFilter(pArchive, SelectionFilter);
    NuSetProgressUpdater(pArchive, ProgressUpdater);
    NuSetErrorHandler(pArchive, ErrorHandler);
    /*NuSetErrorMessageHandler(pArchive, ErrorMessageHandler);*/

    /* handle "-0" flag */
    if (NState_GetModNoCompression(pState)) {
        err = NuSetValue(pArchive, kNuValueDataCompression, kNuCompressNone);
        BailError(err);
    }
    /* handle "-z" flag */
    if (NState_GetModCompressDeflate(pState)) {
        err = NuSetValue(pArchive, kNuValueDataCompression, kNuCompressDeflate);
        BailError(err);
    }
    /* handle "-zz" flag */
    if (NState_GetModCompressBzip2(pState)) {
        err = NuSetValue(pArchive, kNuValueDataCompression, kNuCompressBzip2);
        BailError(err);
    }

    /* handle "-f" and "-u" flags */
    /* (BUG: if "-f" is set, creating a new archive is impossible) */
    if (NState_GetModFreshen(pState) || NState_GetModUpdate(pState)) {
        err = NuSetValue(pArchive, kNuValueOnlyUpdateOlder, true);
        BailError(err);
    }
    if (NState_GetModFreshen(pState)) {
        err = NuSetValue(pArchive, kNuValueHandleExisting, kNuMustOverwrite);
        BailError(err);
    }

    DBUG(("--- enabling ShrinkIt compatibility mode\n"));
    err = NuSetValue(pArchive, kNuValueMimicSHK, true);
    BailError(err);

    /* this probably isn't needed here, but set it anyway */
    if (strcmp(SYSTEM_DEFAULT_EOL, "\r") == 0)
        err = NuSetValue(pArchive, kNuValueEOL, kNuEOLCR);
    else if (strcmp(SYSTEM_DEFAULT_EOL, "\n") == 0)
        err = NuSetValue(pArchive, kNuValueEOL, kNuEOLLF);
    else if (strcmp(SYSTEM_DEFAULT_EOL, "\r\n") == 0)
        err = NuSetValue(pArchive, kNuValueEOL, kNuEOLCRLF);
    else {
        Assert(0);
        err = kNuErrInternal;
        ReportError(err, "Unknown SYSTEM_DEFAULT_EOL '%s'", SYSTEM_DEFAULT_EOL);
        goto bail;
    }
    BailError(err);

    /*(void) NuSetValue(pArchive, kNuValueAllowDuplicates, true);*/

bail:
    Free(tempName);
    if (err != kNuErrNone && pArchive != NULL) {
        /* clean up */
        NuAbort(pArchive);
        (void) NuClose(pArchive);
        NState_SetNuArchive(pState, NULL);
    }
    return err;
}
Example #13
0
/*
 * Add a new thread to a record.
 *
 * In some cases, you aren't allowed to add a thread whose type matches
 * one that already exists.  This applies to data threads and filenames,
 * but not to comments, control threads, or IIgs icons.  You also can't
 * add a disk image thread when there are data-class threads, or vice-versa.
 *
 * This is the first and last place we do this sort of checking.  If
 * an illegal situation gets past this function, it will either get
 * caught with a fatal assert or (if NDEBUG is defined) not at all.
 *
 * On success, the NuThreadIdx of the newly-created record will be placed
 * in "*pThreadIdx", and "pDataSource" will be owned by NufxLib.
 */
NuError Nu_AddThread(NuArchive* pArchive, NuRecordIdx recIdx,
    NuThreadID threadID, NuDataSource* pDataSource, NuThreadIdx* pThreadIdx)
{
    NuError err;
    NuRecord* pRecord;
    NuThreadMod* pThreadMod = NULL;
    NuThreadFormat threadFormat;

    /* okay for pThreadIdx to be NULL */
    if (recIdx == 0 || pDataSource == NULL)
        return kNuErrInvalidArg;

    if (Nu_IsReadOnly(pArchive))
        return kNuErrArchiveRO;
    err = Nu_GetTOCIfNeeded(pArchive);
    BailError(err);

    /*
     * Find the record.  If it doesn't exist in the copy set, check to
     * see if it's in the "new" set.
     */
    err = Nu_FindRecordForWriteByIdx(pArchive, recIdx, &pRecord);
    if (err == kNuErrRecIdxNotFound &&
        Nu_RecordSet_GetLoaded(&pArchive->newRecordSet))
    {
        err = Nu_RecordSet_FindByIdx(&pArchive->newRecordSet, recIdx, &pRecord);
    }
    BailError(err);
    Assert(pRecord != NULL);

    /*
     * Do some tests, looking for specific types of threads that conflict
     * with what we're trying to add.
     */
    err = Nu_OkayToAddThread(pArchive, pRecord, threadID);
    BailError(err);

    /*
     * Decide if we want to compress the data from this source.  If the
     * data is already compressed (as indicated by the data source) or
     * this type of thread isn't compressible (e.g. it's a filename), then
     * we don't compress it.  Otherwise, we use whatever compression mode
     * is currently configured.
     */
    if (Nu_DataSourceGetThreadFormat(pDataSource) == kNuThreadFormatUncompressed &&
        Nu_IsCompressibleThreadID(threadID))
    {
        threadFormat = Nu_ConvertCompressValToFormat(pArchive,
                        pArchive->valDataCompression);
    } else {
        threadFormat = kNuThreadFormatUncompressed;
    }
    DBUG(("--- using threadFormat = %d\n", threadFormat));

    /* create a new ThreadMod (which makes a copy of the data source) */
    err = Nu_ThreadModAdd_New(pArchive, threadID, threadFormat, pDataSource,
            &pThreadMod);
    BailError(err);
    Assert(pThreadMod != NULL);

    /* add the thread mod to the record */
    Nu_RecordAddThreadMod(pRecord, pThreadMod);
    if (pThreadIdx != NULL)
        *pThreadIdx = pThreadMod->entry.add.threadIdx;
    pThreadMod = NULL;   /* successful, don't free */

    /*
     * If we've got a header filename and we're adding a filename thread,
     * we don't want to write the record header name when we reconstruct
     * the record.
     */
    if (threadID == kNuThreadIDFilename && pRecord->recFilenameLength) {
        DBUG(("+++ gonna drop the filename\n"));
        pRecord->dropRecFilename = true;
    }

bail:
    if (pThreadMod != NULL)
        Nu_ThreadModFree(pArchive, pThreadMod);
    if (err == kNuErrNone && pDataSource != NULL) {
        /* on success, we have ownership of the data source.  ThreadMod
           made its own copy, so get rid of this one */
        Nu_DataSourceFree(pDataSource);
    }
    return err;
}
void QTEffects_RespondToDialogSelection (OSErr theErr)
{
	Boolean					myDialogWasCancelled = false;
	short					myResID = movieInDataForkResID;
	UInt16					myMovieIter;
	short					mySrcMovieRefNum = 0;
	Movie					myPrevSrcMovie = NULL;
	Track					myPrevSrcTrack = NULL;
	Movie					myNextSrcMovie = NULL;
	Track					myNextSrcTrack = NULL;
	short					myDestMovieRefNum = 0;
	FSSpec					myFile;
	Boolean					myIsSelected = false;
	Boolean					myIsReplacing = false;	
	StringPtr 				myPrompt = QTUtils_ConvertCToPascalString(kEffectsSaveMoviePrompt);
	StringPtr 				myFileName = QTUtils_ConvertCToPascalString(kEffectsSaveMovieFileName);
	Movie					myDestMovie = NULL;
	Fixed					myDestMovieWidth, myDestMovieHeight;
	ImageDescriptionHandle	myDesc = NULL;
	Track					videoTrackFX, videoTrackA, videoTrackB;
	Media					videoMediaFX, videoMediaA, videoMediaB;
	TimeValue				myCurrentDuration = 0;
	TimeValue				myReturnedDuration;
	Boolean					isFirstTransition = true;
	TimeValue				myMediaTransitionDuration;
	TimeValue				myMediaFXStartTime, myMediaFXDuration;
	OSType					myEffectCode;
	long					myFlags = createMovieFileDeleteCurFile | createMovieFileDontCreateResFile;
	long					myLong;
	OSErr					myErr = noErr;

	// standard parameter box has been dismissed, so remember that fact
	gEffectsDialog = 0L;
	
	myDialogWasCancelled = (theErr == userCanceledErr);
	
	// we're finished with the effect list and movie posters	
	QTDisposeAtomContainer(gEffectList);
	
	if (gPosterA != NULL)
		KillPicture(gPosterA);
		
	if (gPosterB != NULL)
		KillPicture(gPosterB);
	
	// when the sign says stop, then stop
	if (myDialogWasCancelled)
		goto bail;

	// add atoms naming the sources to gEffectSample
	myLong = EndianU32_NtoB(kSourceOneName);
	QTInsertChild(gEffectSample, kParentAtomIsContainer, kEffectSourceName, 1, 0, sizeof(myLong), &myLong, NULL);

	myLong = EndianU32_NtoB(kSourceTwoName);
	QTInsertChild(gEffectSample, kParentAtomIsContainer, kEffectSourceName, 2, 0, sizeof(myLong), &myLong, NULL);
	
	// extract the 'what' atom to find out what kind of effect it is
	{
		QTAtom			myEffectAtom;
		QTAtomID		myEffectAtomID;
		long			myEffectCodeSize;
		Ptr				myEffectCodePtr;

		myEffectAtom = QTFindChildByIndex(gEffectSample, kParentAtomIsContainer, kParameterWhatName, kParameterWhatID, &myEffectAtomID);
		
		myErr = QTLockContainer(gEffectSample);
		BailError(myErr);

		myErr = QTGetAtomDataPtr(gEffectSample, myEffectAtom, &myEffectCodeSize, &myEffectCodePtr);
		BailError(myErr);

		if (myEffectCodeSize != sizeof(OSType)) {
			myErr = paramErr;
			goto bail;
		}
		
		myEffectCode = *(OSType *)myEffectCodePtr;		// "tsk"
		myEffectCode = EndianU32_BtoN(myEffectCode);	// because the data is read from an atom container
		
		myErr = QTUnlockContainer(gEffectSample);
		BailError(myErr);
	}

	// ask the user for the name of the new movie file
	QTFrame_PutFile(myPrompt, myFileName, &myFile, &myIsSelected, &myIsReplacing);
	if (!myIsSelected)
		goto bail;				// deal with user cancelling

	// create a movie file for the destination movie
	myErr = CreateMovieFile(&myFile, FOUR_CHAR_CODE('TVOD'), 0, myFlags, &myDestMovieRefNum, &myDestMovie);
	BailError(myErr);
	
	// open the first file as a movie; call the first movie myPrevSrcMovie
	myErr = OpenMovieFile(&gSpecList[0], &mySrcMovieRefNum, fsRdPerm);
	BailError(myErr);
	
	myErr = NewMovieFromFile(&myPrevSrcMovie, mySrcMovieRefNum, NULL, NULL, 0, NULL);
	BailError(myErr);
	
	myErr = CloseMovieFile(mySrcMovieRefNum);
	BailError(myErr);
	
	// if the movie is shorter than kMinimumDuration, scale it to that length
	SetMovieTimeScale(myPrevSrcMovie, kTimeScale);
	myErr = QTEffects_GetFirstVideoTrackInMovie(myPrevSrcMovie, &myPrevSrcTrack);
	BailNil(myPrevSrcTrack);
	
	if (GetTrackDuration(myPrevSrcTrack) < kMinimumDuration) {
		myErr = ScaleTrackSegment(myPrevSrcTrack, 0, GetTrackDuration(myPrevSrcTrack), kMinimumDuration);
		BailError(myErr);
	}
	
	// find out how big the first movie is; we'll use it as the size of all our tracks
	GetTrackDimensions(myPrevSrcTrack, &myDestMovieWidth, &myDestMovieHeight);
	
#if USES_MAKE_IMAGE_DESC_FOR_EFFECT
	// create a new sample description for the effect,
	// which is just an image description specifying the effect and its dimensions
	myErr = MakeImageDescriptionForEffect(myEffectCode, &myDesc);
	if (myErr != noErr)
		BailError(myErr);
#else
	// create a new sample description for the effect,
	// which is just an image description specifying the effect and its dimensions
	myDesc = (ImageDescriptionHandle)NewHandleClear(sizeof(ImageDescription));
	BailNil(myDesc);
	
	(**myDesc).idSize = sizeof(ImageDescription);
	(**myDesc).cType = myEffectCode;
	(**myDesc).hRes = 72L << 16;
	(**myDesc).vRes = 72L << 16;
	(**myDesc).dataSize = 0L;
	(**myDesc).frameCount = 1;
	(**myDesc).depth = 0;
	(**myDesc).clutID = -1;
#endif
	
	// fill in the fields of the sample description
	(**myDesc).vendor = kAppleManufacturer;
	(**myDesc).temporalQuality = codecNormalQuality;
	(**myDesc).spatialQuality = codecNormalQuality;
	(**myDesc).width = FixRound(myDestMovieWidth);
	(**myDesc).height = FixRound(myDestMovieHeight);

	// add three video tracks to the destination movie:
	// 	- videoTrackFX is where the effects and stills live; it's user-visible.
	//	- videoTrackA is where the "source A"s for effects live; it's hidden by the input map
	//	- videoTrackB is where the "source B"s for effects live; it's hidden by the input map
	videoTrackFX = NewMovieTrack(myDestMovie, myDestMovieWidth, myDestMovieHeight, 0);
	BailNil(videoTrackFX);
	videoMediaFX = NewTrackMedia(videoTrackFX, VideoMediaType, kTimeScale, NULL, 0);
	BailNil(videoMediaFX);
	myErr = BeginMediaEdits(videoMediaFX);
	BailError(myErr);
	
	videoTrackA = NewMovieTrack(myDestMovie, myDestMovieWidth, myDestMovieHeight, 0);
	BailNil(videoTrackA);
	videoMediaA = NewTrackMedia(videoTrackA, VideoMediaType, kTimeScale, NULL, 0);
	BailNil(videoMediaA);

	videoTrackB = NewMovieTrack(myDestMovie, myDestMovieWidth, myDestMovieHeight, 0);
	BailNil(videoTrackB);
	videoMediaB = NewTrackMedia(videoTrackB, VideoMediaType, kTimeScale, NULL, 0);
	BailNil(videoMediaB);

	// create the input map
	{
		long				myRefIndex1, myRefIndex2;
		QTAtomContainer		myInputMap;
		QTAtom				myInputAtom;
		OSType				myInputType;

		QTNewAtomContainer(&myInputMap);

		// first input
		if (videoTrackA) {
		
			AddTrackReference(videoTrackFX, videoTrackA, kTrackModifierReference, &myRefIndex1);
			QTInsertChild(myInputMap, kParentAtomIsContainer, kTrackModifierInput, myRefIndex1, 0, 0, NULL, &myInputAtom);
	
			myInputType = EndianU32_NtoB(kTrackModifierTypeImage);
			QTInsertChild(myInputMap, myInputAtom, kTrackModifierType, 1, 0, sizeof(myInputType), &myInputType, NULL);
	
			myLong = EndianU32_NtoB(kSourceOneName);
			QTInsertChild(myInputMap, myInputAtom, kEffectDataSourceType, 1, 0, sizeof(myLong), &myLong, NULL);
		}

		// second input
		if (videoTrackB) {
		
			AddTrackReference(videoTrackFX, videoTrackB, kTrackModifierReference, &myRefIndex2);
			QTInsertChild(myInputMap, kParentAtomIsContainer, kTrackModifierInput, myRefIndex2, 0, 0, NULL, &myInputAtom);
	
			myInputType = EndianU32_NtoB(kTrackModifierTypeImage);
			QTInsertChild(myInputMap, myInputAtom, kTrackModifierType, 1, 0, sizeof(myInputType), &myInputType, NULL);
	
			myLong = EndianU32_NtoB(kSourceTwoName);
			QTInsertChild(myInputMap, myInputAtom, kEffectDataSourceType, 1, 0, sizeof(myLong), &myLong, NULL);
		}

		// set that map
		SetMediaInputMap(GetTrackMedia(videoTrackFX), myInputMap);
		
		QTDisposeAtomContainer(myInputMap);
	}

	myCurrentDuration = 0;

#if MAKE_STILL_SECTIONS
	// copy the first sample of the first video track of the first movie to videoTrackFX, with duration kStillDuration.
	myErr = CopyPortionOfTrackToTrack(myPrevSrcTrack, eStartPortion + eMiddlePortion, videoTrackFX, myCurrentDuration, &myReturnedDuration);
	BailError(myErr);
	
	myCurrentDuration += myReturnedDuration;
#endif 

	// now process any remaining files
	myMovieIter = 1;
	while (myMovieIter < gSpecCount) {
		
		// open the next file as a movie; call it nextSourceMovie
		myErr = OpenMovieFile(&gSpecList[myMovieIter], &mySrcMovieRefNum, fsRdPerm);
		BailError(myErr);
		
		myErr = NewMovieFromFile(&myNextSrcMovie, mySrcMovieRefNum, NULL, NULL, 0, NULL);
		BailError(myErr);
		
		// we're done with the movie file, so close it
		myErr = CloseMovieFile(mySrcMovieRefNum);
		BailError(myErr);
		
		// if the movie is shorter than kMinimumDuration, scale it to that length
		SetMovieTimeScale(myNextSrcMovie, kTimeScale);
		myErr = QTEffects_GetFirstVideoTrackInMovie(myNextSrcMovie, &myNextSrcTrack);
		BailNil(myNextSrcTrack);
		
		if (GetTrackDuration(myNextSrcTrack) < kMinimumDuration) {
			myErr = ScaleTrackSegment(myNextSrcTrack, 0, GetTrackDuration(myNextSrcTrack), kMinimumDuration);
			BailError(myErr);
		}

		// create a transition effect from the previous source movie's first video sample to the next source movie's first video sample
		// (the effect should have duration kEffectDuration);
		// this involves adding one sample to each of the three video tracks:
		
		//    sample from previous source movie	 -> videoTrackA
		myErr = QTEffects_CopyPortionOfTrackToTrack(myPrevSrcTrack, eFinishPortion, videoTrackA, myCurrentDuration, &myReturnedDuration);
		BailError(myErr);
		
		//    sample from next source movie    	 -> videoTrackB
		myErr = QTEffects_CopyPortionOfTrackToTrack(myNextSrcTrack, eStartPortion, videoTrackB, myCurrentDuration, &myReturnedDuration);
		BailError(myErr);
		
		//    effect sample                 	  -> videoTrackFX
		if (isFirstTransition) {
			myMediaTransitionDuration = myReturnedDuration;
			myMediaFXStartTime = GetMediaDuration(videoMediaFX);
			myErr = AddMediaSample(videoMediaFX, gEffectSample, 0, GetHandleSize(gEffectSample), myMediaTransitionDuration, (SampleDescriptionHandle)myDesc, 1, 0, NULL);
			BailError(myErr);
			
			myMediaFXDuration = GetMediaDuration(videoMediaFX) - myMediaFXStartTime;
			isFirstTransition = false;
		}
		
		myErr = InsertMediaIntoTrack(videoTrackFX, myCurrentDuration, myMediaFXStartTime, myMediaFXDuration, FixRatio(myReturnedDuration, myMediaTransitionDuration));
		BailError(myErr);
		
		myCurrentDuration += myReturnedDuration;
		
#if MAKE_STILL_SECTIONS
		// copy the first video sample of myNextSrcMovie to videoTrackFX, with duration kStillDuration.
		myErr = QTEffects_CopyPortionOfTrackToTrack(myNextSrcTrack, eMiddlePortion + (myMovieIter + 1 == theSpecCount) ? eFinishPortion : 0, videoTrackFX, myCurrentDuration, &myReturnedDuration);
		BailError(myErr);
		
		myCurrentDuration += myReturnedDuration;
#endif // MAKE_STILL_SECTIONS
		
		// dispose of previous source movie.  
		DisposeMovie(myPrevSrcMovie);
		
		myPrevSrcMovie = myNextSrcMovie;
		myPrevSrcTrack = myNextSrcTrack;
		myNextSrcMovie = NULL;
		myNextSrcTrack = NULL;
		
		myMovieIter++;
	} // while
	
	myErr = EndMediaEdits(videoMediaFX);
	BailError(myErr);

	myErr = AddMovieResource(myDestMovie, myDestMovieRefNum, &myResID, "\pMovie 1");
	BailError(myErr);
	
	CloseMovieFile(myDestMovieRefNum);
	
	if (myPrevSrcMovie != NULL)
		DisposeMovie(myPrevSrcMovie);
		
	DisposeMovie(myDestMovie);
	
bail:
	free(myPrompt);
	free(myFileName);

	QTDisposeAtomContainer(gEffectSample);
	DisposeHandle((Handle)myDesc);

	return;
}
OSErr QTEffects_DisplayDialogForSources (FSSpec *theSpecList, UInt16 theSpecCount)
{
	OSErr					myErr = noErr;
	
	// make sure that there are enough sources: you can't make an omelette without enough eggs
	if (theSpecCount < 2) {
		myErr = paramErr;
		goto bail;
	}

	// assign source count to a global, so QTEffects_RespondToDialogSelection has access to it
	gSpecCount = theSpecCount;		
	
	// get a poster frame for the first two movies
	if (theSpecCount >= 1)
		gPosterA = QTEffects_GetPosterPictFromFirstVideoTrackInMovieFile(&theSpecList[0]);
	
	if (theSpecCount >= 2)
		gPosterB = QTEffects_GetPosterPictFromFirstVideoTrackInMovieFile(&theSpecList[1]);
	
	// ask the user to select a two-source effect

	myErr = QTNewAtomContainer(&gEffectSample);
	BailError(myErr);
	
	myErr = QTGetEffectsList(&gEffectList, 2, 2, 0);		// min == max == 2
	BailError(myErr);
	
	myErr = QTCreateStandardParameterDialog(gEffectList, gEffectSample, 0, &gEffectsDialog);
	BailError(myErr);
	
	// insert poster frames into dialog
	if (gPosterA != NULL) {
		QTParamPreviewRecord			pr;

		pr.sourcePicture = gPosterA;
		pr.sourceID = 1;
		QTStandardParameterDialogDoAction(gEffectsDialog, pdActionSetPreviewPicture, &pr);
	}

	if (gPosterB != NULL) {
		QTParamPreviewRecord			pr;

		pr.sourcePicture = gPosterB;
		pr.sourceID = 2;
		QTStandardParameterDialogDoAction(gEffectsDialog, pdActionSetPreviewPicture, &pr);
	}
	
	// now, the frontmost window is the standard effects parameter dialog box;
	// on the Mac, we call QTEffects_HandleEffectsDialogEvents in our main event loop
	// to find and process events targeted at the effects parameter dialog box; on Windows,
	// we need to use a different strategy: we install a modeless dialog callback procedure
	// that is called internally by QTML

#if TARGET_OS_WIN32
	gDoneWithDialog = false;
	
	// force the dialog box to be drawn
	{
		EventRecord			myEvent = {0};
		
		QTEffects_EffectsDialogCallback(&myEvent, FrontWindow(), 0);
	}
	
	SetModelessDialogCallbackProc(FrontWindow(), (QTModelessCallbackUPP)QTEffects_EffectsDialogCallback);
	QTMLSetWindowWndProc(FrontWindow(), QTEffects_CustomDialogWndProc);
#endif
	
bail:
	return(myErr);
}
Example #16
0
/*
 * Update the contents of a pre-sized thread, such as a filename or
 * comment thread.
 *
 * The data from the source must fit within the limits of the existing
 * thread.  The source data is never compressed, and must not come from
 * a compressed source.
 *
 * You aren't allowed to update threads that have been deleted.  Updating
 * newly-added threads isn't possible, since they aren't really threads yet.
 */
NuError Nu_UpdatePresizedThread(NuArchive* pArchive, NuThreadIdx threadIdx,
    NuDataSource* pDataSource, int32_t* pMaxLen)
{
    NuError err;
    NuThreadMod* pThreadMod = NULL;
    NuRecord* pFoundRecord;
    NuThread* pFoundThread;

    if (pDataSource == NULL) {
        err = kNuErrInvalidArg;
        goto bail;
    }

    /* presized threads always contain uncompressed data */
    if (Nu_DataSourceGetThreadFormat(pDataSource) !=
        kNuThreadFormatUncompressed)
    {
        err = kNuErrBadFormat;
        Nu_ReportError(NU_BLOB, err,
            "presized threads can't hold compressed data");
        goto bail;
    }

    if (Nu_IsReadOnly(pArchive))
        return kNuErrArchiveRO;
    err = Nu_GetTOCIfNeeded(pArchive);
    BailError(err);

    /*
     * Find the thread in the "copy" set.  (If there isn't a copy set,
     * make one.)
     */
    err = Nu_FindThreadForWriteByIdx(pArchive, threadIdx, &pFoundRecord,
            &pFoundThread);
    BailError(err);

    if (!Nu_IsPresizedThreadID(NuGetThreadID(pFoundThread)) ||
        !(pFoundThread->thCompThreadEOF >= pFoundThread->thThreadEOF))
    {
        err = kNuErrNotPreSized;
        Nu_ReportError(NU_BLOB, err, "invalid thread for update");
        goto bail;
    }

    if (pMaxLen != NULL)
        *pMaxLen = pFoundThread->thCompThreadEOF;

    /*
     * Check to see if somebody is trying to delete this, or has already
     * updated it.
     */
    if (Nu_ThreadMod_FindByThreadIdx(pFoundRecord, threadIdx) != NULL) {
        DBUG(("--- Tried to modify a deleted or modified thread\n"));
        err = kNuErrModThreadChange;
        goto bail;
    }

    /*
     * Verify that "otherLen" in the data source is less than or equal
     * to our len, if we can.  If the data source is a file on disk,
     * we're not really supposed to look at it until we flush.  We
     * could sneak a peek right now, which would prevent us from aborting
     * the entire operation when it turns out the file won't fit, but
     * that violates our semantics (and besides, the application really
     * should've done that already).
     *
     * If the data source is from a file, we just assume it'll fit and
     * let the chips fall where they may later on.
     */
    if (Nu_DataSourceGetType(pDataSource) != kNuDataSourceFromFile) {
        if (pFoundThread->thCompThreadEOF <
            Nu_DataSourceGetOtherLen(pDataSource))
        {
            err = kNuErrPreSizeOverflow;
            Nu_ReportError(NU_BLOB, err, "can't put %u bytes into %u",
                Nu_DataSourceGetOtherLen(pDataSource),
                pFoundThread->thCompThreadEOF);
            goto bail;
        }

        /* check for zero-length and excessively long filenames */
        if (NuGetThreadID(pFoundThread) == kNuThreadIDFilename &&
            (Nu_DataSourceGetOtherLen(pDataSource) == 0 ||
             Nu_DataSourceGetOtherLen(pDataSource) > kNuReasonableFilenameLen))
        {
            err = kNuErrInvalidFilename;
            Nu_ReportError(NU_BLOB, err, "invalid filename (%u bytes)",
                Nu_DataSourceGetOtherLen(pDataSource));
            goto bail;
        }
    }

    /*
     * Looks like it'll fit, and it's the right kind of data.  Create
     * an "update" threadMod.  Note this copies the data source.
     */
    Assert(pFoundThread->thThreadFormat == kNuThreadFormatUncompressed);
    err = Nu_ThreadModUpdate_New(pArchive, threadIdx, pDataSource, &pThreadMod);
    BailError(err);
    Assert(pThreadMod != NULL);

    /* add the thread mod to the record */
    Nu_RecordAddThreadMod(pFoundRecord, pThreadMod);

    /*
     * NOTE: changes to filename threads will be picked up later and
     * incorporated into the record's threadFilename.  We don't worry
     * about the record header filename, because we might be doing an
     * update-in-place and that prevents us from removing the filename
     * (doing so would change the size of the archive).  No need to
     * do any filename-specific changes here.
     */

bail:
    return err;
}
Example #17
0
/*
 * Open the archive in read-only mode.  We use "file mode" for a file, or
 * "streaming mode" for stdin.
 */
NuError OpenArchiveReadOnly(NulibState* pState)
{
    NuError err;
    NuArchive* pArchive = NULL;

    Assert(pState != NULL);

    if (IsFilenameStdin(NState_GetArchiveFilename(pState))) {
        err = NuStreamOpenRO(stdin, &pArchive);
        if (err != kNuErrNone) {
            ReportError(err, "unable to open stdin archive");
            if (err == kNuErrIsBinary2)
                err = kNuErrNotNuFX;    /* we can't seek back, so forget BNY */
            goto bail;
        }
        /*
         * Since the archive is on stdin, we can't ask the user questions.
         * On a UNIX system we could open /dev/tty, but that's not portable,
         * and I don't think archives on stdin are going to be popular
         * enough to make this worth doing.
         */
        NState_SetInputUnavailable(pState, true);
    } else {
        err = NuOpenRO(NState_GetArchiveFilename(pState), &pArchive);
        if (err != kNuErrNone) {
            if (err != kNuErrIsBinary2) {
                ReportError(err, "unable to open '%s'",
                    NState_GetArchiveFilename(pState));
            }
            goto bail;
        }
    }

    /* introduce them */
    NState_SetNuArchive(pState, pArchive);
    err = NuSetExtraData(pArchive, pState);

    NuSetSelectionFilter(pArchive, SelectionFilter);
    NuSetOutputPathnameFilter(pArchive, OutputPathnameFilter);
    NuSetProgressUpdater(pArchive, ProgressUpdater);
    NuSetErrorHandler(pArchive, ErrorHandler);
    /*NuSetErrorMessageHandler(pArchive, ErrorMessageHandler);*/

    /* set the EOL conversion */
    if (NState_GetModConvertAll(pState))
        err = NuSetValue(pArchive, kNuValueConvertExtractedEOL, kNuConvertOn);
    else if (NState_GetModConvertText(pState))
        err = NuSetValue(pArchive, kNuValueConvertExtractedEOL, kNuConvertAuto);
    else
        err = NuSetValue(pArchive, kNuValueConvertExtractedEOL, kNuConvertOff);
    BailError(err);

    /* if we're converting EOL, we probably ought to do this too */
    err = NuSetValue(pArchive, kNuValueStripHighASCII, true);
    BailError(err);

    /* handle "-s" flag */
    if (NState_GetModOverwriteExisting(pState)) {
        err = NuSetValue(pArchive, kNuValueHandleExisting, kNuAlwaysOverwrite);
        BailError(err);
    }

    /* handle "-f" and "-u" flags (this overrides "-s" during extraction) */
    if (NState_GetModFreshen(pState) || NState_GetModUpdate(pState)) {
        err = NuSetValue(pArchive, kNuValueOnlyUpdateOlder, true);
        BailError(err);
    }
    if (NState_GetModFreshen(pState)) {
        err = NuSetValue(pArchive, kNuValueHandleExisting, kNuMustOverwrite);
        BailError(err);
    }

    DBUG(("--- enabling ShrinkIt compatibility mode\n"));
    err = NuSetValue(pArchive, kNuValueMimicSHK, true);
    BailError(err);

    /* handy for some malformed archives */
    err = NuSetValue(pArchive, kNuValueHandleBadMac, true);
    BailError(err);

/*
    DBUG(("--- enabling 'mask dataless' mode\n"));
    err = NuSetValue(pArchive, kNuValueMaskDataless, true);
    BailError(err);
*/

    if (strcmp(SYSTEM_DEFAULT_EOL, "\r") == 0)
        err = NuSetValue(pArchive, kNuValueEOL, kNuEOLCR);
    else if (strcmp(SYSTEM_DEFAULT_EOL, "\n") == 0)
        err = NuSetValue(pArchive, kNuValueEOL, kNuEOLLF);
    else if (strcmp(SYSTEM_DEFAULT_EOL, "\r\n") == 0)
        err = NuSetValue(pArchive, kNuValueEOL, kNuEOLCRLF);
    else {
        Assert(0);
        err = kNuErrInternal;
        ReportError(err, "Unknown SYSTEM_DEFAULT_EOL '%s'", SYSTEM_DEFAULT_EOL);
        goto bail;
    }
    BailError(err);

bail:
    if (err != kNuErrNone && pArchive != NULL) {
        /* clean up */
        (void) NuClose(pArchive);
        NState_SetNuArchive(pState, NULL);
    }
    return err;
}