/* File: DummySave.c Copyright 1990 by Thomas Knoll. Think C source file for DummySave example. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "ExportInterface.h" #define nil 0L #define Length(string) (*(unsigned char *)(string)) /* The value of global variables are not preserved between invocations of the plug-in, since the plug-in's resource file is closed. To keep values around longer, make them part of the following structure. */ typedef struct TPermanent { short dummy1; /* None are actually used in this example */ } TPermanent; TPermanent gPermanent; short gResult; ExportRecordPtr gStuff; short gFRefNum; short gVRefNum; /*****************************************************************************/ /* Calls the host's TestAbort function */ Boolean TestAbort (void) { return CallPascalB (gStuff->abortProc); } /*****************************************************************************/ /* Calls the host's UpdateProgress procedure */ void UpdateProgress (done, total) long done; long total; { CallPascal (done, total, gStuff->progressProc); } /*****************************************************************************/ /* Sets the global variables to their default values. */ void InitGlobals (void) { } /*****************************************************************************/ /* Centers a dialog template 1/3 of the way down on the main screen. */ void CenterDialog (dt) DialogTHndl dt; #define menuHeight 20 { Rect r; short width; short height; width = screenBits.bounds.right; height = screenBits.bounds.bottom; r = (**dt).boundsRect; OffsetRect (&r, -r.left, -r.top); OffsetRect (&r, (width - r.right) / 2, (height - r.bottom - menuHeight) / 3 + menuHeight); (**dt).boundsRect = r; } #undef menuHeight /*****************************************************************************/ /* Displays the about dialog box for the plug-in module. */ void DoAbout (void) #define dialogID 17000 { short item; DialogPtr dp; DialogTHndl dt; dt = (DialogTHndl) GetResource ('DLOG', dialogID); HNoPurge ((Handle) dt); CenterDialog (dt); dp = GetNewDialog (dialogID, nil, (WindowPtr) -1); ModalDialog (nil, &item); DisposDialog (dp); HPurge ((Handle) dt); } #undef dialogID /*****************************************************************************/ /* Prepare to export an image. If the plug-in module needs only a limited amount of memory, it can lower the value of the 'maxData' field. */ void DoPrepare (void) { if (gStuff->maxData > 0x80000) gStuff->maxData = 0x80000; } /*****************************************************************************/ /* Request next block of the image */ void RequestNext (top) short top; { long count; /* Compute maximum number of rows we should request at once */ count = gStuff->maxData / gStuff->imageSize.h / gStuff->planes; if (count < 1) count = 1; /* Request next block of the image */ gStuff->loPlane = 0; gStuff->hiPlane = gStuff->planes - 1; gStuff->theRect.left = 0; gStuff->theRect.right = gStuff->imageSize.h; gStuff->theRect.top = top; if (top + count > gStuff->imageSize.v) gStuff->theRect.bottom = gStuff->imageSize.v; else gStuff->theRect.bottom = top + count; } /*****************************************************************************/ /* Verifies that the image mode is supported. Prompts the user for a file name to save the image to, and requests the first block of of image data. */ void DoStart (void) #define kStringsID 17000 { OSErr err; Point where; Str255 prompt; SFReply reply; DialogTHndl dt; /* This plug-in does not support bitmap images */ if (gStuff->imageMode == exportModeBitmap) { gResult = exportBadMode; return; } /* Get prompt string */ GetIndString (prompt, kStringsID, 1); /* Center dialog */ dt = (DialogTHndl) GetResource ('DLOG', putDlgID); HNoPurge ((Handle) dt); CenterDialog (dt); where.v = (**dt).boundsRect.top; where.h = (**dt).boundsRect.left; HPurge ((Handle) dt); /* Ask the user */ SFPutFile (where, prompt, gStuff->filename, nil, &reply); if (!reply.good) { gResult = 1; return; } gVRefNum = reply.vRefNum; err = FSDelete (reply.fName, gVRefNum); err = Create (reply.fName, gVRefNum, '????', '????'); if (err != noErr) { gResult = err; return; } err = FSOpen (reply.fName, gVRefNum, &gFRefNum); if (err != noErr) { gResult = err; return; } /* Request first block of image */ RequestNext (0); } #undef kStringsID /*****************************************************************************/ /* Processes the next chunk of the image. */ void DoContinue (void) { OSErr err; short row; long count; for (row = gStuff->theRect.top; row < gStuff->theRect.bottom; row++) { /* See if user was aborted the operation */ if (TestAbort ()) { gResult = 1; return; } /* Update the progress indicator */ UpdateProgress ((long) row, (long) gStuff->imageSize.v); /* Write out this row of the image */ count = gStuff->planes * (long) gStuff->imageSize.h; err = FSWrite (gFRefNum, &count, (Ptr) ((long) (gStuff->data) + gStuff->rowBytes * (row - gStuff->theRect.top))); if (err != noErr) { gResult = err; return; } } /* Request next block of image */ RequestNext (gStuff->theRect.bottom); } /*****************************************************************************/ /* This routine will always be called if DoStart does not return an error (even if DoContinue returns an error or the user aborts the operation). This allows the module to perform any needed cleanup. */ void DoFinish (void) { OSErr err; /* Close the file */ err = FSClose (gFRefNum); if (err != noErr) { gResult = err; return; } /* Flush the volume */ err = FlushVol (nil, gVRefNum); if (err != noErr) { gResult = err; return; } /* Clear the image's unsaved changes flag */ gStuff->dirty = false; } /*****************************************************************************/ /* Main dispatching routine. Initializes and sets up the global variables, and performs the operation specified by the selector. */ pascal void main (selector, stuff, data, result) short selector; ExportRecordPtr stuff; long *data; short *result; { Boolean firstTime; /* Allow access to global variables */ RememberA0 (); SetUpA4 (); /* Copy the current quickdraw globals into the plug-in local copy */ asm { MOVE.L (A5),A0 ; Get address of real quickdraw globals SUB.L #126,A0 ; Move to start LEA randSeed,A1 ; Get address of local copy MOVE.W #64,D0 ; Globals are 65 words long @1 MOVE.W (A0)+,(A1)+ ; Copy a word DBF D0,@1 ; Move to next word } /* See if this is the first time called */ if (!*data) { /* Allocate a handle to hold permanent values */ *data = (long) NewHandle ((long) sizeof (TPermanent)); if (!*data) { *result = memFullErr; RestoreA4 (); return; } /* Initialize the permanent values */ InitGlobals (); } /* Else restore permanent values */ else BlockMove (*((Handle) *data), (Ptr) &gPermanent, (long) sizeof (TPermanent)); /* Perform the requested operation */ gStuff = stuff; gResult = noErr; switch (selector) { case exportSelectorAbout: DoAbout (); break; case exportSelectorPrepare: DoPrepare (); break; case exportSelectorStart: DoStart (); break; case exportSelectorContinue: DoContinue (); break; case exportSelectorFinish: DoFinish (); break; default: gResult = exportBadParameters; } *result = gResult; /* Save permanent values */ BlockMove ((Ptr) &gPermanent, *((Handle) *data), (long) sizeof (TPermanent)); /* Restore the application's A4 register */ RestoreA4 (); }