source/fileCache.c

/****************************************************/
/*                                                  */
/*  File:       fileCache.c                         */
/*                                                  */
/*  Program:    Imageer                             */
/*                                                  */
/*  By:         Jason Hodges-Harris                 */
/*                                                  */
/*  Created:    12/01/95  00:00:00 AM               */
/*                                                  */
/*  Version:    1.0.0d3                             */
/*                                                  */
/*  Copyright:  © 1995-96 Apple Computer, Inc.,     */ 
/*                  all rights reserved.            */      
/*                                                  */
/****************************************************/
 
 
/**** Macintosh Toolbox Headers *****/
 
#ifndef __FILES__
#include <Files.h>
#endif
 
#ifndef __FOLDERS__
#include <Folders.h>
#endif
 
#ifndef __SCRIPT__
#include <Script.h>
#endif
 
#ifndef __STANDARDFILE__
#include <StandardFile.h>
#endif
 
#ifndef __STRING__
#include <string.h>
#endif
 
#ifndef __STRINGS__
#include <Strings.h>
#endif
 
#ifndef __TEXTUTILS__
#include <TextUtils.h>
#endif
 
#ifndef __TYPES__
#include <Types.h>
#endif
 
 
/****   Application headers and prototypes   ****/
 
 
#ifndef __IMAGEERAPPHEADER__
#include "Imageer.app.h"
#endif
 
#ifndef __IMAGEERPROTOSHEADER__
#include "Imageer.protos.h"
#endif
 
 
/****   Global variables    ****/
 
extern long     gTempFolderDirID,
                gTempFileCount;
extern short    gTempFolderVolRef;
 
 
/****   Test to find if temporary folder exists ****/
 
//  function tests for existence of the Temporary Folder inside the System Folder
//  and creates folder if not present
 
#pragma segment imageCache
OSErr   FindTempFolder(void)
{
    OSErr       error = noErr;
    Boolean     tempExists = false;
 
    error = FindFolder(kOnSystemDisk, kTemporaryFolderType,
                       kCreateFolder,&gTempFolderVolRef,
                       &gTempFolderDirID);
    if (error)
        DisplayAlert (rGenWarning,rFileIOMessages,iCreateTempFldrErr);  
    return error;
}
 
 
/****   Remove image docs temporary files   ****/
 
// Delete temp file(s) specified in boolean input parameters
// used to hold Color QD cache information for undo/redo
 
#pragma segment imageCache
OSErr   RemoveTempFile(ImageDocHndl theDocHndl, Boolean delUndoFile, Boolean delRedoFile)
{
    OSErr       error = noErr;
    
    HLock((Handle)theDocHndl);
    if (delUndoFile)
    {
        error = FSpDelete(&(*theDocHndl)->theTempUndoFileSpec);
        (*theDocHndl)->hasUndoTemp = false;
    }
    if (delRedoFile)
    {
        error |= FSpDelete(&(*theDocHndl)->theTempRedoFileSpec);
        (*theDocHndl)->hasRedoTemp = false;
    }
    HUnlock((Handle)theDocHndl);
    error = noErr;  // currently ignore error checking 
    if (error)
        DisplayAlert (rGenWarning,rFileIOMessages,iDeleteTempFileErr);
    return error;
}
 
 
/****   Save temporary Undo file    ****/
 
// save cache file information from current image window prior
// to image manipulation after removing previous obselete temporary file(s).
 
#pragma segment imageCache
OSErr   SaveTempImageFile(ImageDocHndl theDocHndl, short tempFileOp)
{
    Str255          theMenuString,
                    theResString;
    OSErr           error = noErr;
    Boolean         isRedoTempFile = false;
    
    (*theDocHndl)->theLastAction = tempFileOp;
    GetMenuItemText(GetMHandle(mEdit),iUndo,theMenuString); 
    GetIndString (theResString,rMenuItems,iOpRedo);
    if (EqualString(theMenuString,theResString,true,true))
        isRedoTempFile = true;
    if (!isRedoTempFile)
        RemoveTempFile(theDocHndl, true, true);
    else
        RemoveTempFile(theDocHndl, false, true);
    switch (tempFileOp)
    {
        case kPixMapOp:
            error = SavePixMaptoTemp(theDocHndl, isRedoTempFile);
            if (error)
            {
                (*theDocHndl)->theUndoState = kCannotUndo;
                DebugStr("\pError saving image PixMap to temp file.");
            }
        break;
        case kColorTableOp:
            error = SaveCTabtoTemp(theDocHndl, isRedoTempFile);
            if (error)
            {
                (*theDocHndl)->theUndoState = kCannotUndo;
                DebugStr("\pError saving image colorTable to temp file.");
            }
        break;
        case kGXTransformOp:
        break;
    }
    SetUndoItemText((*theDocHndl)->theUndoState);
    return error;
}
 
 
/****   Load temporary file ****/
 
// Retrieve stored temporary file information and use to revert offscreen image to old state
 
#pragma segment imageCache
OSErr   LoadTempImageFile(ImageDocHndl theDocHndl)
{
    Str255          theMenuString,
                    theResString;
    OSErr           error = noErr;
    short           tempFileOpType = (*theDocHndl)->theLastAction;
    Boolean         isRedoTempFile = false;
    
    (*theDocHndl)->theLastAction = tempFileOpType;
    GetMenuItemText(GetMHandle(mEdit),iUndo,theMenuString); 
    GetIndString (theResString,rMenuItems,iOpRedo);
    if (EqualString(theMenuString,theResString,true,true))
        isRedoTempFile = true;
    switch (tempFileOpType)
    {
        case kPixMapOp:
            if (!isRedoTempFile)
                error = SavePixMaptoTemp(theDocHndl, true);
            error |= LoadTemptoPixMap(theDocHndl, isRedoTempFile);
            if (error)
                DebugStr("\pError loading image PixMap from temp file.");
        break;
        case kColorTableOp:
            if (!isRedoTempFile)
                error = SaveCTabtoTemp(theDocHndl, true);
            error |= LoadTemptoCTab(theDocHndl, isRedoTempFile);
            if (error)
                DebugStr("\pError loading image color table from temp file.");
        break;
        case kGXTransformOp:
        break;
    }
    if (isRedoTempFile)
        (*theDocHndl)->theUndoState = kCanUndo;
    SetUndoItemText((*theDocHndl)->theUndoState);
    return error;
}
 
 
/****   Save Pixmap Data to temporary file  ****/
 
// Store locked down offscreen GWorld Pixmap in temp file for undo/redo operation
 
#pragma segment imageCache
OSErr   SavePixMaptoTemp(ImageDocHndl theDocHndl, Boolean isRedoFile)
{
    PixMapHandle    thePixMapHndl = nil;
    Ptr             pixMapData;
    long            width,
                    height,
                    fileSize,
                    diskSpace,
                    count;
    Str63           tempFileName,
                    fileNumStr;
    short           fileRefNum,
                    theVolRef;
    OSErr           error = noErr;
 
    thePixMapHndl = GetGWorldPixMap((**theDocHndl).theImageWorld);
    if (PixMap32Bit(thePixMapHndl))
        SaveSetMMUMode(true);
    if (!LockPixels(thePixMapHndl))
        error = kFailedLockPixels;
    if (!error)
    {
        width = (**thePixMapHndl).rowBytes & 0x3FFF;
        height = (**theDocHndl).theImageYSize;
        fileSize = width*height;
        error = GetVInfo(gTempFolderVolRef, 0,&theVolRef, &diskSpace);
        if (error)
        {
            DebugStr("\pCouldn't get information for Temporory folder volume.");
            return kDefaultAppError;
        }
        // Test for adequate space on hard disk to save file information.
        // Display warning dialog and return without saving data if disk is full
        if (fileSize > diskSpace)
        {
            DisplayAlert (rGenWarning,rFileIOMessages,iDiskFullErr);
            return kDefaultAppError;
        }
        pixMapData = GetPixBaseAddr(thePixMapHndl);
        if (isRedoFile)
        {
            (*theDocHndl)->theTempRedoFileSpec.vRefNum = gTempFolderVolRef;
            (*theDocHndl)->theTempRedoFileSpec.parID = gTempFolderDirID;
            (*theDocHndl)->hasRedoTemp = true;
            (*theDocHndl)->theUndoState = kCanRedo;
        }
        else
        {
            (*theDocHndl)->theTempUndoFileSpec.vRefNum = gTempFolderVolRef;
            (*theDocHndl)->theTempUndoFileSpec.parID = gTempFolderDirID;
            (*theDocHndl)->hasUndoTemp = true;
            (*theDocHndl)->theUndoState = kCanUndo;
        }
        // Create new temporary file name
        // using an incremental number appended to filename to keep unique.
        strcpy((char*)tempFileName,(char*)"\pTempFile");
        NumToString(gTempFileCount,fileNumStr);
        gTempFileCount++;
        p2cstr(tempFileName);
        p2cstr(fileNumStr);
        strcat((char*)tempFileName,(char *)fileNumStr);
        c2pstr((char*)tempFileName);
        // Save undo/redo file after first creating and opening new file.
        if (!isRedoFile)
        {
            strcpy((char*)(*theDocHndl)->theTempUndoFileSpec.name,(char*)tempFileName);
            error = FSpCreate(&(*theDocHndl)->theTempUndoFileSpec,
                               (OSType)AppCreator, 'Imtp', smSystemScript);
            if (!error)
                error = FSpOpenDF(&(*theDocHndl)->theTempUndoFileSpec,fsRdWrPerm,&fileRefNum);
        }
        else
        {
            strcpy((char*)(*theDocHndl)->theTempRedoFileSpec.name,(char*)tempFileName);
            error = FSpCreate(&(*theDocHndl)->theTempRedoFileSpec,
                               (OSType)AppCreator, 'Imtp', smSystemScript);
            if (!error)
                error = FSpOpenDF(&(*theDocHndl)->theTempRedoFileSpec,fsRdWrPerm,&fileRefNum);
        }
        if (!error)
        {
            for (count = 0;count < height;count++)
            {
                error = FSWrite(fileRefNum,&width,pixMapData);
                if (error)
                    DebugStr("\pError Writing Pixmap to Temp File.");
                pixMapData+=width;
            }
            error = FSClose(fileRefNum);
        }
        UnlockPixels(thePixMapHndl);
    }
    SaveSetMMUMode(false);
    return error;
}
 
 
/****   Load Pixmap Data from temp file ****/
 
// Retrieve temporary file. Locking down the Offscreen Pixmap,
// before reading in the data directly.
 
#pragma segment imageCache
OSErr   LoadTemptoPixMap(ImageDocHndl theDocHndl, Boolean isRedoFile)
{
    PixMapHandle    thePixMapHndl = nil;
    Ptr             pixMapData;
    long            width,
                    height,
                    count;
    short           fileRefNum;
    OSErr           error = noErr;
 
    thePixMapHndl = GetGWorldPixMap((**theDocHndl).theImageWorld);
    if (PixMap32Bit(thePixMapHndl))
        SaveSetMMUMode(true);
    if (!LockPixels(thePixMapHndl))
        error = kFailedLockPixels;
    if (!error)
    {
        width = (**thePixMapHndl).rowBytes & 0x3FFF;
        height = (**theDocHndl).theImageYSize;
        pixMapData = GetPixBaseAddr(thePixMapHndl); // base addr of GWorld
        if (isRedoFile)
            error = FSpOpenDF(&(*theDocHndl)->theTempRedoFileSpec,fsRdWrPerm,&fileRefNum);
        else
            error = FSpOpenDF(&(*theDocHndl)->theTempUndoFileSpec,fsRdWrPerm,&fileRefNum);
        if (!error)
        {
            for (count = 0;count < height;count++)
            {
                FSRead(fileRefNum,&width,pixMapData);
                pixMapData+=width;
            }
            error = FSClose(fileRefNum);
        }
        UnlockPixels(thePixMapHndl);
    }
    SaveSetMMUMode(false);
    return error;
}
 
 
/****   Save Color QuickDraw color table to temp file   ****/
 
// For indexed Color QuickDraw images, the color table
// information of the offscreen copy of the image is saved. 
// The Color Table's handle is locked down, size determined,
// a new file created and the contents written out
// with a unique name if no error is reported.
 
#pragma segment imageCache
OSErr   SaveCTabtoTemp(ImageDocHndl theDocHndl, Boolean isRedoFile)
{
    CTabHandle      cTabHndl;
    long            fileSize,
                    diskSpace;
    short           fileRefNum,
                    theVolRef;
    OSErr           error = noErr;
    Str63           tempFileName,
                    fileNumStr;
    
    HLock((Handle)(*(*theDocHndl)->theImageWorld->portPixMap)->pmTable);
    cTabHndl = (*(*theDocHndl)->theImageWorld->portPixMap)->pmTable;
    fileSize = GetHandleSize((Handle)cTabHndl);
    error = GetVInfo(gTempFolderVolRef, 0,&theVolRef, &diskSpace);
    if (error)
    {
        DebugStr("\pCouldn't get information for Temporory folder volume.");
        return kDefaultAppError;
    }
    if (fileSize > diskSpace)
    {
        DisplayAlert (rGenWarning,rFileIOMessages,iDiskFullErr);
        return kDefaultAppError;
    }
    if (isRedoFile)
    {
        (*theDocHndl)->theTempRedoFileSpec.vRefNum = gTempFolderVolRef;
        (*theDocHndl)->theTempRedoFileSpec.parID = gTempFolderDirID;
        (*theDocHndl)->hasRedoTemp = true;
        (*theDocHndl)->theUndoState = kCanRedo;
    }
    else
    {
        (*theDocHndl)->theTempUndoFileSpec.vRefNum = gTempFolderVolRef;
        (*theDocHndl)->theTempUndoFileSpec.parID = gTempFolderDirID;
        (*theDocHndl)->hasUndoTemp = true;
        (*theDocHndl)->theUndoState = kCanUndo;
    }
    strcpy((char*)tempFileName,(char*)"\pTempFile");
    NumToString(gTempFileCount,fileNumStr);
    gTempFileCount++;
    p2cstr(tempFileName);
    p2cstr(fileNumStr);
    strcat((char*)tempFileName,(char *)fileNumStr);
    c2pstr((char*)tempFileName);
    if (isRedoFile)
    {
        strcpy((char*)(*theDocHndl)->theTempRedoFileSpec.name,(char*)tempFileName);
        error = FSpCreate(&(*theDocHndl)->theTempRedoFileSpec,
                           (OSType)AppCreator, 'Imtp', smSystemScript);
        if (!error)
            error = FSpOpenDF(&(*theDocHndl)->theTempRedoFileSpec,fsRdWrPerm,&fileRefNum);
        if (!error)
        {
            FSWrite(fileRefNum,&fileSize,(*cTabHndl));
            error = FSClose(fileRefNum);
        }
    }
    else
    {
        strcpy((char*)(*theDocHndl)->theTempUndoFileSpec.name,(char*)tempFileName);
        error = FSpCreate(&(*theDocHndl)->theTempUndoFileSpec,
                           (OSType)AppCreator, 'Imtp', smSystemScript);
        if (!error)
            error = FSpOpenDF(&(*theDocHndl)->theTempUndoFileSpec,fsRdWrPerm,&fileRefNum);
        if (!error)
        {
            error = FSWrite(fileRefNum,&fileSize,*cTabHndl);
            if (error)
                DebugStr("\pError Writing Pixmap to Temp File.");
            error = FSClose(fileRefNum);
        }
    }
    HUnlock((Handle)cTabHndl);
    return error;
}
 
 
/****   Load temporary file to Color QuickDraw color table  ****/
 
// Load the saved color table cache file into the locked down
// handle of a Color QD image's offscreen ColorTable handle
// structure and force the Color Manager to recalculate the Color Table.
 
#pragma segment imageCache
OSErr   LoadTemptoCTab(ImageDocHndl theDocHndl, Boolean isRedoFile)
{
    CTabHandle      cTabHndl;
    long            fileSize;
    short           fileRefNum;
    OSErr           error = noErr;
    
    HLock((Handle)(*(*theDocHndl)->theImageWorld->portPixMap)->pmTable);
    cTabHndl = (*(*theDocHndl)->theImageWorld->portPixMap)->pmTable;
    fileSize = GetHandleSize((Handle)cTabHndl);
    if (isRedoFile)
        error = FSpOpenDF(&(*theDocHndl)->theTempRedoFileSpec,fsRdWrPerm,&fileRefNum);
    else
        error = FSpOpenDF(&(*theDocHndl)->theTempUndoFileSpec,fsRdWrPerm,&fileRefNum);
    if (!error)
    {
        FSRead(fileRefNum,&fileSize,(*cTabHndl));
        error = FSClose(fileRefNum);
    }
    CTabChanged(cTabHndl);
    HUnlock((Handle)cTabHndl);
    return error;
}