mirror of
https://github.com/aaronsgiles/uuUndo.git
synced 2024-11-24 14:31:25 +00:00
1 line
29 KiB
C
1 line
29 KiB
C
/******************************************************************************
|
||
**
|
||
** Project Name: DropShell
|
||
** File Name: DSUserProcs.c
|
||
**
|
||
** Description: Specific AppleEvent handlers used by the DropBox
|
||
**
|
||
*******************************************************************************
|
||
** A U T H O R I D E N T I T Y
|
||
*******************************************************************************
|
||
**
|
||
** Initials Name
|
||
** -------- -----------------------------------------------
|
||
** LDR Leonard Rosenthol
|
||
** MTC Marshall Clow
|
||
** SCS Stephan Somogyi
|
||
**
|
||
*******************************************************************************
|
||
** R E V I S I O N H I S T O R Y
|
||
*******************************************************************************
|
||
**
|
||
** Date Time Author Description
|
||
** -------- ----- ------ ---------------------------------------------
|
||
** 01/25/92 LDR Removed the use of const on the userDataHandle
|
||
** 12/09/91 LDR Added the new SelectFile userProc
|
||
** Added the new Install & DisposeUserGlobals procs
|
||
** Modified PostFlight to only autoquit on odoc, not pdoc
|
||
** 11/24/91 LDR Added the userProcs for pdoc handler
|
||
** Cleaned up the placement of braces
|
||
** Added the passing of a userDataHandle
|
||
** 10/29/91 SCS Changes for THINK C 5
|
||
** 10/28/91 LDR Officially renamed DropShell (from QuickShell)
|
||
** Added a bunch of comments for clarification
|
||
** 10/06/91 00:02 MTC Converted to MPW C
|
||
** 04/09/91 00:02 LDR Added to Projector
|
||
**
|
||
******************************************************************************/
|
||
|
||
#include "DSGlobals.h"
|
||
#include "DSUserProcs.h"
|
||
#include "DSDialogs.h"
|
||
|
||
#include "DSUtilsASG.h"
|
||
|
||
#include <Folders.h>
|
||
#include <GestaltEqu.h>
|
||
#include <ImageCompression.h>
|
||
#include <ctype.h>
|
||
#include <string.h>
|
||
#include <stdio.h>
|
||
|
||
//==================================================================================================================================
|
||
// Globals
|
||
//==================================================================================================================================
|
||
|
||
typedef struct odocQueue {
|
||
struct odocQueue *next;
|
||
FSSpec spec;
|
||
Handle data;
|
||
} odocQueue, *odocQueuePtr;
|
||
|
||
enum {
|
||
cacheData = 0x10,
|
||
dontCache = 0x20
|
||
};
|
||
|
||
static Boolean gAborted = false;
|
||
|
||
static char *gInputBuffer = nil, *gOutputBuffer = nil;
|
||
static char *gInputBufferBase = nil, *gOutputBufferBase = nil;
|
||
static char *gInputBufferPtr = nil, *gOutputBufferPtr = nil;
|
||
|
||
static ParamBlockRec gInputPB1, gInputPB2;
|
||
static ParamBlockRec gOutputPB1, gOutputPB2;
|
||
static HParamBlockRec gCloseOutputPB;
|
||
static HParamBlockRec gOpenOutputPB;
|
||
static HParamBlockRec gDeleteInputPB;
|
||
|
||
static short gInputRefNum = 0, gOutputRefNum = 0;
|
||
|
||
static Size gInputBufferLeft = 0, gOutputBufferCount = 0;
|
||
static Size gTotalSize = 0, gBytesRead = 0, gLinesProcessed = 0;
|
||
|
||
static Boolean gLastInputBuffer = false, gFoundEndCode = false;
|
||
static odocQueuePtr godocQueue = nil;
|
||
|
||
|
||
static IOCompletionUPP gGenericCompletion = nil;
|
||
|
||
Boolean gProcessing = false, gHasCQD = false;
|
||
|
||
enum {
|
||
kInputBufferSize = 32L * 1024L,
|
||
kOutputBufferSize = 32L * 1024L,
|
||
|
||
kExtensionMapType = 'E2Ty',
|
||
kExtensionMapID = 0
|
||
};
|
||
|
||
static OSErr OpenInputFile(FSSpecPtr theSpec);
|
||
static OSErr FillInputBuffer(void);
|
||
static OSErr CloseInputFile(FSSpecPtr theSpec);
|
||
static char *GetNextInputLine(Size *length, Boolean *badUU);
|
||
static char *GetNextUUInputLine(void);
|
||
static OSErr OpenOutputFile(FSSpecPtr inSpec, FSSpecPtr outSpec, char *outName);
|
||
static OSErr CreateOutputFile(FSSpecPtr outSpec, char *outName, OSType creator, OSType type);
|
||
static void MapOutputExtension(char *outname, OSType *creator, OSType *type);
|
||
static OSErr FlushOutputBuffer(void);
|
||
static OSErr CloseOutputFile(FSSpecPtr theSpec);
|
||
static OSErr DecodeUULine(char *line);
|
||
static void AddToQueue(FSSpec *theSpec, Handle userData);
|
||
static void ProcessQueue(void);
|
||
static void DisableMenus(void);
|
||
static void EnableMenus(void);
|
||
|
||
#if defined(powerc) || defined(__powerc)
|
||
static pascal void GenericCompletion(ParmBlkPtr paramBlock);
|
||
#else
|
||
static pascal void GenericCompletion(void);
|
||
#endif
|
||
|
||
//==================================================================================================================================
|
||
// This routine is called during init time.
|
||
//
|
||
// It allows you to install more AEVT Handlers beyond the standard four
|
||
//==================================================================================================================================
|
||
|
||
#pragma segment Main
|
||
pascal void InstallOtherEvents(void)
|
||
{
|
||
}
|
||
|
||
|
||
//==================================================================================================================================
|
||
// This routine is called when an OAPP event is received.
|
||
//
|
||
// Currently, all it does is set the gOApped flag, so you know that
|
||
// you were called initally with no docs, and therefore you shouldn't
|
||
// quit when done processing any following odocs.
|
||
//==================================================================================================================================
|
||
|
||
#pragma segment Main
|
||
pascal void OpenApp(void)
|
||
{
|
||
gOApped = true;
|
||
}
|
||
|
||
|
||
//==================================================================================================================================
|
||
// This routine is called when an QUIT event is received.
|
||
// We simply set the global done flag so that the main event loop can
|
||
// gracefully exit. We DO NOT call ExitToShell for two reasons:
|
||
// 1) It is a pretty ugly thing to do, but more importantly
|
||
// 2) The Apple event manager will get REAL upset!
|
||
//==================================================================================================================================
|
||
|
||
#pragma segment Main
|
||
pascal void QuitApp(void)
|
||
{
|
||
gDone = true;
|
||
}
|
||
|
||
|
||
//==================================================================================================================================
|
||
// This routine is the first one called when an ODOC or PDOC event is received.
|
||
// In this routine you would place code used to setup structures, etc.
|
||
// which would be used in a 'for all docs' situation (like "Archive all
|
||
// dropped files")
|
||
//
|
||
// Obviously, the opening boolean tells you whether you should be opening
|
||
// or printing these files based on the type of event recieved.
|
||
//
|
||
// userDataHandle is a handle that you can create & use to store your own
|
||
// data structs. This dataHandle will be passed around to the other
|
||
// odoc/pdoc routines so that you can get at your data without using
|
||
// globals - just like the new StandardFile.
|
||
//
|
||
// We also return a boolean to tell the caller if you support this type
|
||
// of event. By default, our dropboxes don't support the pdoc, so when
|
||
// opening is FALSE, we return FALSE to let the caller send back the
|
||
// proper error code to the AEManager.
|
||
//==================================================================================================================================
|
||
|
||
#pragma segment Main
|
||
pascal Boolean PreFlightDocs(Boolean opening, Handle *userDataHandle)
|
||
{
|
||
if (!opening) return false;
|
||
if (gProcessing) return true;
|
||
gAborted = false;
|
||
ParamText("\p", "\p", "\p", "\p");
|
||
if (GenericProgress(codecProgressOpen, 0, 0) == codecAbortErr) return false;
|
||
DisableMenus();
|
||
return true; // we support opening, but not printing - see above
|
||
}
|
||
|
||
|
||
//==================================================================================================================================
|
||
// This routine is called for each file passed in the ODOC event.
|
||
//
|
||
// In this routine you would place code for processing each file/folder/disk that
|
||
// was dropped on top of you.
|
||
//==================================================================================================================================
|
||
|
||
#pragma segment Main
|
||
pascal void OpenDoc(FSSpecPtr myFSSPtr, Boolean opening, Handle userDataHandle)
|
||
{
|
||
FSSpec outFile;
|
||
OSErr theErr;
|
||
char *line;
|
||
|
||
if (gAborted) return;
|
||
if (gProcessing) {
|
||
AddToQueue(myFSSPtr, userDataHandle);
|
||
return;
|
||
}
|
||
ParamText("\p", "\p", "\p", "\p");
|
||
UpdateDialogItem(FrontWindow(), progressText2);
|
||
GenericProgress(codecProgressForceUpdatePercent, 0, 0);
|
||
theErr = OpenInputFile(myFSSPtr);
|
||
if (theErr == noErr) {
|
||
gLinesProcessed = 0;
|
||
do {
|
||
Size length;
|
||
Boolean bad;
|
||
line = GetNextInputLine(&length, &bad);
|
||
if (!(++gLinesProcessed & 0x3f))
|
||
if (GenericProgress(codecProgressUpdatePercent, FixRatio((gBytesRead - gInputBufferLeft) >> 8, gTotalSize >> 8), 0) == codecAbortErr) {
|
||
gAborted = true;
|
||
line = nil;
|
||
break;
|
||
}
|
||
} while (line && (line[0] != 'b' || line[1] != 'e' || line[2] != 'g' || line[3] != 'i' ||
|
||
line[4] != 'n' || line[5] != ' '));
|
||
if (line) {
|
||
theErr = OpenOutputFile(myFSSPtr, &outFile, &line[10]);
|
||
if (theErr == noErr) {
|
||
do {
|
||
line = GetNextUUInputLine();
|
||
if (line) theErr = DecodeUULine(line);
|
||
} while (theErr == noErr && line);
|
||
if (theErr != codecAbortErr) FlushOutputBuffer();
|
||
else gAborted = true;
|
||
CloseOutputFile(&outFile);
|
||
}
|
||
GenericProgress(codecProgressForceUpdatePercent, 0x10000, 0);
|
||
}
|
||
CloseInputFile(myFSSPtr);
|
||
ForceFolderUpdate(outFile.vRefNum, outFile.parID);
|
||
}
|
||
}
|
||
|
||
|
||
//==================================================================================================================================
|
||
// This routine is the last routine called as part of an ODOC event.
|
||
//
|
||
// In this routine you would place code to process any structures, etc.
|
||
// that you setup in the PreflightDocs routine.
|
||
//
|
||
// If you created a userDataHandle in the PreFlightDocs routines, this is
|
||
// the place to dispose of it since the Shell will NOT do it for you!
|
||
//==================================================================================================================================
|
||
|
||
#pragma segment Main
|
||
pascal void PostFlightDocs(Boolean opening, Handle userDataHandle)
|
||
{
|
||
if (gProcessing) return;
|
||
ProcessQueue();
|
||
GenericProgress(codecProgressClose, 0, 0);
|
||
EnableMenus();
|
||
if (opening && !gOApped) gDone = true;
|
||
}
|
||
|
||
|
||
//==================================================================================================================================
|
||
// This routine is called when the user chooses "Select File<6C>" from the
|
||
// File Menu.
|
||
//
|
||
// Currently it simply calls the new StandardGetFile routine to have the
|
||
// user select a single file (any type, numTypes = -1) and then calls the
|
||
// SendODOCToSelf routine in order to process it.
|
||
//
|
||
// The reason we send an odoc to ourselves is two fold: 1) it keeps the code
|
||
// cleaner as all file openings go through the same process, and 2) if events
|
||
// are ever recordable, the right things happen (this is called Factoring!)
|
||
//
|
||
// Modification of this routine to only select certain types of files, selection
|
||
// of multiple files, and/or handling of folder & disk selection is left
|
||
// as an exercise to the reader.
|
||
//==================================================================================================================================
|
||
|
||
pascal void SelectFile(void)
|
||
{
|
||
StandardFileReply stdReply;
|
||
SFTypeList theTypeList;
|
||
|
||
UserDialogActivate(FrontWindow(), false);
|
||
StandardGetFile(NULL, -1, theTypeList, &stdReply);
|
||
UserDialogActivate(FrontWindow(), true);
|
||
if (stdReply.sfGood) SendODOCToSelf(&stdReply.sfFile);
|
||
}
|
||
|
||
//==================================================================================================================================
|
||
// This routine is called during the program's initialization and gives you
|
||
// a chance to allocate or initialize any of your own globals that your
|
||
// dropbox needs.
|
||
//
|
||
// You return a boolean value which determines if you were successful.
|
||
// Returning false will cause DropShell to exit immediately.
|
||
//==================================================================================================================================
|
||
|
||
pascal Boolean InitUserGlobals(void)
|
||
{
|
||
long resp;
|
||
if (Gestalt(gestaltQuickdrawVersion, &resp) == noErr && resp) gHasCQD = true;
|
||
|
||
gInputBufferBase = gInputBuffer = (char *)NewPtr(kInputBufferSize * 2);
|
||
if (!gInputBuffer) return false;
|
||
|
||
gOutputBufferBase = gOutputBuffer = (char *)NewPtr(kOutputBufferSize * 2);
|
||
if (!gOutputBuffer) return false;
|
||
|
||
gInputPB1.ioParam.ioBuffer = gInputBufferBase + 256;
|
||
gInputPB1.ioParam.ioReqCount = kInputBufferSize - 512;
|
||
gInputPB1.ioParam.ioCompletion = gGenericCompletion;
|
||
gInputPB1.ioParam.ioPosMode = fsAtMark + dontCache;
|
||
gInputPB1.ioParam.ioPosOffset = 0;
|
||
|
||
gInputPB2.ioParam.ioBuffer = gInputBufferBase + kInputBufferSize + 256;
|
||
gInputPB2.ioParam.ioReqCount = kInputBufferSize - 512;
|
||
gInputPB2.ioParam.ioCompletion = gGenericCompletion;
|
||
gInputPB2.ioParam.ioPosMode = fsAtMark + dontCache;
|
||
gInputPB2.ioParam.ioPosOffset = 0;
|
||
|
||
gOutputPB1.ioParam.ioBuffer = gOutputBufferBase;
|
||
gOutputPB1.ioParam.ioCompletion = gGenericCompletion;
|
||
gOutputPB1.ioParam.ioPosMode = fsAtMark + dontCache;
|
||
gOutputPB1.ioParam.ioPosOffset = 0;
|
||
|
||
gOutputPB2.ioParam.ioBuffer = gOutputBufferBase + kOutputBufferSize;
|
||
gOutputPB2.ioParam.ioCompletion = gGenericCompletion;
|
||
gOutputPB2.ioParam.ioPosMode = fsAtMark + dontCache;
|
||
gOutputPB2.ioParam.ioPosOffset = 0;
|
||
|
||
gDeleteInputPB.ioParam.ioResult = 0;
|
||
|
||
LoadPrefs();
|
||
|
||
return true;
|
||
}
|
||
|
||
//==================================================================================================================================
|
||
// This routine is called during the program's cleanup and gives you
|
||
// a chance to deallocate any of your own globals that you allocated
|
||
// in the above routine.
|
||
//==================================================================================================================================
|
||
|
||
pascal void DisposeUserGlobals(void)
|
||
{
|
||
if (gInputBuffer) DisposePtr(gInputBuffer);
|
||
if (gOutputBuffer) DisposePtr(gOutputBuffer);
|
||
CloseUserDialog(FrontWindow());
|
||
SavePrefs();
|
||
}
|
||
|
||
//==================================================================================================================================
|
||
//==================================================================================================================================
|
||
//==================================================================================================================================
|
||
//==================================================================================================================================
|
||
//==================================================================================================================================
|
||
//==================================================================================================================================
|
||
|
||
pascal void HandleFileMenu(short id)
|
||
{
|
||
if (id == 2) CloseUserDialog(FrontWindow());
|
||
else if (id == 4) OpenUserDialog(0, id);
|
||
}
|
||
|
||
OSErr OpenInputFile(FSSpecPtr theSpec)
|
||
{
|
||
static HParamBlockRec openPB;
|
||
static ParamBlockRec eofPB;
|
||
OSErr theErr;
|
||
|
||
// set up the local parameter block to do an asynchronous open
|
||
openPB.fileParam.ioCompletion = gGenericCompletion;
|
||
openPB.fileParam.ioNamePtr = theSpec->name;
|
||
openPB.fileParam.ioVRefNum = theSpec->vRefNum;
|
||
openPB.ioParam.ioPermssn = fsRdPerm;
|
||
openPB.fileParam.ioDirID = theSpec->parID;
|
||
openPB.fileParam.ioResult = 1;
|
||
theErr = PBHOpenDFAsync(&openPB);
|
||
|
||
// give time to other applications as this is happening
|
||
while (openPB.fileParam.ioResult == 1) GiveTime();
|
||
theErr = openPB.fileParam.ioResult;
|
||
|
||
// save the resulting reference number in a global
|
||
gInputPB1.ioParam.ioRefNum = gInputPB2.ioParam.ioRefNum = gInputRefNum = openPB.ioParam.ioRefNum;
|
||
if (theErr == noErr) {
|
||
|
||
// set up the other local parameter block to do an asychronous GetEOF
|
||
eofPB.ioParam.ioCompletion = gGenericCompletion;
|
||
eofPB.ioParam.ioRefNum = gInputRefNum;
|
||
eofPB.ioParam.ioResult = 1;
|
||
theErr = PBGetEOFAsync(&eofPB);
|
||
|
||
// again, give up time to other apps while this happens
|
||
while (eofPB.ioParam.ioResult == 1) GiveTime();
|
||
theErr = eofPB.ioParam.ioResult;
|
||
if (theErr == noErr) {
|
||
|
||
// if everything went ok, store the size in a global, and reset the input reading parameter blocks
|
||
gTotalSize = (long)eofPB.ioParam.ioMisc;
|
||
gBytesRead = gLinesProcessed = 0;
|
||
gLastInputBuffer = gFoundEndCode = false;
|
||
gInputBufferLeft = 0;
|
||
gInputPB1.ioParam.ioResult = gInputPB2.ioParam.ioResult = 0;
|
||
gInputPB1.ioParam.ioActCount = gInputPB2.ioParam.ioActCount = 0;
|
||
|
||
// fill the two input buffers right away
|
||
return FillInputBuffer();
|
||
}
|
||
}
|
||
return theErr;
|
||
}
|
||
|
||
OSErr FillInputBuffer(void)
|
||
{
|
||
Boolean buffer1 = (!gBytesRead || gInputBufferPtr < gInputBufferBase + kInputBufferSize);
|
||
Boolean firstTime = !gBytesRead;
|
||
static ParmBlkPtr pb, oppPB;
|
||
OSErr theErr = noErr;
|
||
|
||
// get pointers to the parameter block for this buffer and for the opposite buffer
|
||
pb = (buffer1) ? &gInputPB1 : &gInputPB2;
|
||
oppPB = (buffer1) ? &gInputPB2 : &gInputPB1;
|
||
|
||
// copy remaining bytes in this buffer to beginning of next buffer
|
||
if (gInputBufferLeft) BlockMove(gInputBufferPtr, oppPB->ioParam.ioBuffer - gInputBufferLeft, gInputBufferLeft);
|
||
gInputBufferPtr = oppPB->ioParam.ioBuffer - gInputBufferLeft;
|
||
|
||
// wait for next buffer to finish, if necessary
|
||
while (oppPB->ioParam.ioResult == 1) GiveTime();
|
||
if (!firstTime && oppPB->ioParam.ioResult == eofErr && !oppPB->ioParam.ioActCount) gLastInputBuffer = true;
|
||
|
||
// adjust the count of bytes left and bytes read
|
||
gInputBufferLeft += oppPB->ioParam.ioActCount;
|
||
gBytesRead += oppPB->ioParam.ioActCount;
|
||
|
||
// now begin loading into the buffer we just skipped out of
|
||
pb->ioParam.ioResult = 1;
|
||
theErr = PBReadAsync(pb);
|
||
if (theErr == eofErr) theErr = noErr;
|
||
|
||
// if this is the first time reading, then we wait for this buffer to load, and load in a second buffer
|
||
if (firstTime) {
|
||
gInputBufferPtr = pb->ioParam.ioBuffer;
|
||
while (pb->ioParam.ioResult == 1) GiveTime();
|
||
gInputBufferLeft = pb->ioParam.ioActCount;
|
||
gBytesRead = pb->ioParam.ioActCount;
|
||
oppPB->ioParam.ioResult = 1;
|
||
theErr = PBReadAsync(oppPB);
|
||
if (theErr == eofErr) theErr = noErr;
|
||
}
|
||
return theErr;
|
||
}
|
||
|
||
OSErr CloseInputFile(FSSpecPtr theSpec)
|
||
{
|
||
static Boolean first = true;
|
||
static HParamBlockRec pb;
|
||
static CMovePBRec cpb;
|
||
OSErr theErr;
|
||
|
||
if (!first) while (pb.ioParam.ioResult == 1) GiveTime();
|
||
else first = false;
|
||
pb.ioParam.ioCompletion = gGenericCompletion;
|
||
pb.ioParam.ioRefNum = gInputRefNum;
|
||
pb.ioParam.ioResult = 1;
|
||
theErr = PBCloseAsync((ParmBlkPtr)&pb);
|
||
if (gFoundEndCode) {
|
||
if ((*gPrefs)->trashSource == kTrashSource) {
|
||
while (pb.ioParam.ioResult == 1) GiveTime();
|
||
FSSpec destSpec = *theSpec;
|
||
theErr = FindFolder(theSpec->vRefNum, kTrashFolderType,
|
||
kCreateFolder, &destSpec.vRefNum, &destSpec.parID);
|
||
if (theErr == noErr) {
|
||
short count = 1;
|
||
Str63 oldName;
|
||
BlockMove(theSpec->name, oldName, *theSpec->name + 1);
|
||
do {
|
||
cpb.ioCompletion = gGenericCompletion;
|
||
cpb.ioNamePtr = theSpec->name;
|
||
cpb.ioVRefNum = theSpec->vRefNum;
|
||
cpb.ioNewName = nil;
|
||
cpb.ioNewDirID = destSpec.parID;
|
||
cpb.ioDirID = theSpec->parID;
|
||
cpb.ioResult = 1;
|
||
theErr = PBCatMoveAsync(&cpb);
|
||
while (cpb.ioResult == 1) GiveTime();
|
||
if (cpb.ioResult == dupFNErr) {
|
||
Str63 newName;
|
||
if (*theSpec->name < 28) theSpec->name[*theSpec->name + 1] = 0;
|
||
else theSpec->name[29] = 0;
|
||
sprintf((char *)&newName[1], "%s %d", &oldName[1], ++count);
|
||
*newName = strlen((char *)&newName[1]);
|
||
pb.fileParam.ioCompletion = gGenericCompletion;
|
||
pb.fileParam.ioNamePtr = theSpec->name;
|
||
pb.fileParam.ioVRefNum = theSpec->vRefNum;
|
||
pb.fileParam.ioDirID = theSpec->parID;
|
||
pb.ioParam.ioMisc = (Ptr)newName;
|
||
theErr = PBHRenameAsync(&pb);
|
||
while (pb.ioParam.ioResult == 1) GiveTime();
|
||
BlockMove(newName, theSpec->name, *newName + 1);
|
||
}
|
||
} while (cpb.ioResult == dupFNErr);
|
||
}
|
||
} else if ((*gPrefs)->trashSource == kDeleteSource) {
|
||
while (pb.ioParam.ioResult == 1) GiveTime();
|
||
pb.fileParam.ioCompletion = gGenericCompletion;
|
||
pb.fileParam.ioNamePtr = theSpec->name;
|
||
pb.fileParam.ioVRefNum = theSpec->vRefNum;
|
||
pb.fileParam.ioDirID = theSpec->parID;
|
||
theErr = PBHDeleteAsync(&pb);
|
||
while (pb.ioParam.ioResult == 1) GiveTime();
|
||
}
|
||
}
|
||
return theErr;
|
||
}
|
||
|
||
char *GetNextInputLine(Size *length, Boolean *badUU)
|
||
{
|
||
OSErr theErr = noErr;
|
||
if (gInputBufferLeft <= 0 && gLastInputBuffer) return nil;
|
||
else if (gInputBufferLeft < 256) theErr = FillInputBuffer();
|
||
if (theErr == noErr) {
|
||
register char *start = gInputBufferPtr;
|
||
register char *p = gInputBufferPtr;
|
||
register char *end = gInputBufferPtr + gInputBufferLeft;
|
||
register char c;
|
||
|
||
do {
|
||
c = *p++;
|
||
if (c == 0x0d || c == 0x0a) break;
|
||
if (c < ' ' || c > '`') *badUU = true;
|
||
} while (p < end);
|
||
p[-1] = 0;
|
||
*length = p - start - 1;
|
||
do {
|
||
c = *p++;
|
||
} while (c == 0x0d && c == 0x0a && p < end);
|
||
p--;
|
||
gInputBufferPtr = p;
|
||
gInputBufferLeft -= (p - start);
|
||
return start;
|
||
}
|
||
return nil;
|
||
}
|
||
|
||
char *GetNextUUInputLine(void)
|
||
{
|
||
register char *line;
|
||
Boolean bad = false;
|
||
Size length;
|
||
do {
|
||
register int count, min, max;
|
||
line = GetNextInputLine(&length, &bad);
|
||
if (!line) return nil;
|
||
if (line[0] == 'e' && line[1] == 'n' && line[2] == 'd' && line[3] == 0) {
|
||
gFoundEndCode = true;
|
||
return nil;
|
||
}
|
||
if (bad) {
|
||
bad = false;
|
||
continue;
|
||
}
|
||
count = (line[0] - ' ');
|
||
if (count < 0 || count > 45) continue;
|
||
min = ((count << 2) + 2) / 3;
|
||
max = (((min + 3) >> 2) << 2) + 1;
|
||
length--;
|
||
if (length < min || length > max) continue;
|
||
return line;
|
||
} while (line);
|
||
return nil;
|
||
}
|
||
|
||
OSErr DecodeUULine(char *line)
|
||
{
|
||
register int count = (*line++) - ' ';
|
||
register int i;
|
||
register char *src, *dst;
|
||
register char c1, c2;
|
||
OSErr theErr = noErr;
|
||
|
||
if ((gOutputBufferCount + count + 256 + 3) > kOutputBufferSize) theErr = FlushOutputBuffer();
|
||
for (i = 0, src = line, dst = gOutputBufferPtr; i < count; i += 3) {
|
||
c1 = (*src++ - ' ') & 0x3f;
|
||
c2 = (*src++ - ' ') & 0x3f;
|
||
*dst++ = ((c1 << 2) | (c2 >> 4)) & 0xff;
|
||
c1 = (*src++ - ' ') & 0x3f;
|
||
*dst++ = ((c2 << 4) | (c1 >> 2)) & 0xff;
|
||
c2 = (*src++ - ' ') & 0x3f;
|
||
*dst++ = ((c1 << 6) | c2) & 0xff;
|
||
}
|
||
gOutputBufferCount += count;
|
||
gOutputBufferPtr = dst;
|
||
if (!(++gLinesProcessed & 0x3f))
|
||
theErr = GenericProgress(codecProgressUpdatePercent, FixRatio((gBytesRead - gInputBufferLeft) >> 8, gTotalSize >> 8), 0);
|
||
return theErr;
|
||
}
|
||
|
||
OSErr OpenOutputFile(FSSpecPtr inSpec, FSSpecPtr outSpec, char *outName)
|
||
{
|
||
register char *p = outName;
|
||
register int count = 0;
|
||
OSErr theErr = noErr;
|
||
OSType creator, type;
|
||
register char c;
|
||
|
||
// first figure out the creator and type based on the output filename (assume the eol is already set up)
|
||
MapOutputExtension(outName, &creator, &type);
|
||
|
||
// now copy the filename into the FSSpec, limiting the length to 31 characters
|
||
*outSpec = *inSpec;
|
||
outSpec->name[31] = 0;
|
||
do {
|
||
c = *p++;
|
||
} while (c && ++count < 32);
|
||
p[-1] = 0;
|
||
strncpy((char *)&outSpec->name[1], outName, 30);
|
||
*outSpec->name = strlen((char *)&outSpec->name[1]);
|
||
ParamText(outSpec->name, "\p", "\p", "\p");
|
||
UpdateDialogItem(FrontWindow(), progressText2);
|
||
|
||
// do the actual creation, avoiding namespace conflicts
|
||
theErr = CreateOutputFile(outSpec, outName, creator, type);
|
||
|
||
// assuming everything else went okay, we finally open the file for writing
|
||
if (theErr == noErr) {
|
||
gOpenOutputPB.ioParam.ioCompletion = gGenericCompletion;
|
||
gOpenOutputPB.fileParam.ioNamePtr = outSpec->name;
|
||
gOpenOutputPB.fileParam.ioVRefNum = outSpec->vRefNum;
|
||
gOpenOutputPB.ioParam.ioPermssn = fsRdWrPerm;
|
||
gOpenOutputPB.fileParam.ioDirID = outSpec->parID;
|
||
gOpenOutputPB.ioParam.ioResult = 1;
|
||
theErr = PBHOpenDFAsync(&gOpenOutputPB);
|
||
}
|
||
|
||
// reset all the output-related variables, and return
|
||
gOutputBufferPtr = gOutputBuffer;
|
||
gOutputBufferCount = 0;
|
||
gOutputPB1.ioParam.ioResult = gOutputPB2.ioParam.ioResult = 0;
|
||
return theErr;
|
||
}
|
||
|
||
#define ASYNC_CREATE 1
|
||
|
||
OSErr CreateOutputFile(FSSpecPtr outSpec, char *outName, OSType creator, OSType type)
|
||
{
|
||
static HParamBlockRec createPB;
|
||
static HParamBlockRec fInfoPB;
|
||
register int count = 0;
|
||
OSErr theErr = noErr;
|
||
|
||
// here begins our loop to find a valid name for the new output file
|
||
do {
|
||
|
||
#if ASYNC_CREATE
|
||
// now set up the local parameter block to do an asynchronous create
|
||
createPB.ioParam.ioCompletion = gGenericCompletion;
|
||
createPB.fileParam.ioNamePtr = outSpec->name;
|
||
createPB.fileParam.ioVRefNum = outSpec->vRefNum;
|
||
createPB.fileParam.ioDirID = outSpec->parID;
|
||
createPB.ioParam.ioResult = 1;
|
||
theErr = PBHCreateAsync(&createPB);
|
||
|
||
// give time to other processes while this happens
|
||
while (createPB.ioParam.ioResult == 1) GiveTime();
|
||
if (theErr == noErr) theErr = createPB.ioParam.ioResult;
|
||
#else
|
||
theErr = FSpCreate(outSpec, creator, type, 0);
|
||
#endif
|
||
|
||
// if a duplicate file name error occurred, bump up the last digit
|
||
if (theErr == dupFNErr) {
|
||
strncpy((char *)&outSpec->name[1], outName, 28);
|
||
outSpec->name[29] = 0;
|
||
*outSpec->name = strlen((char *)&outSpec->name[1]);
|
||
outSpec->name[++*outSpec->name] = '.';
|
||
outSpec->name[++*outSpec->name] = '0' + count++;
|
||
}
|
||
|
||
} while (theErr == dupFNErr);
|
||
|
||
#if ASYNC_CREATE
|
||
// now get the default file information from the Finder
|
||
if (theErr == noErr) {
|
||
fInfoPB.ioParam.ioCompletion = gGenericCompletion;
|
||
fInfoPB.fileParam.ioNamePtr = outSpec->name;
|
||
fInfoPB.fileParam.ioVRefNum = outSpec->vRefNum;
|
||
fInfoPB.fileParam.ioFDirIndex = 0;
|
||
fInfoPB.fileParam.ioDirID = outSpec->parID;
|
||
fInfoPB.ioParam.ioResult = 1;
|
||
theErr = PBHGetFInfoAsync(&fInfoPB);
|
||
}
|
||
|
||
// give time to other processes while this happens
|
||
while (fInfoPB.ioParam.ioResult == 1) GiveTime();
|
||
if (theErr == noErr) theErr = fInfoPB.ioParam.ioResult;
|
||
|
||
// then set the type and creator for this file
|
||
if (theErr == noErr) {
|
||
fInfoPB.fileParam.ioFlFndrInfo.fdCreator = creator;
|
||
fInfoPB.fileParam.ioFlFndrInfo.fdType = type;
|
||
fInfoPB.fileParam.ioDirID = outSpec->parID;
|
||
fInfoPB.ioParam.ioResult = 1;
|
||
theErr = PBHSetFInfoAsync(&fInfoPB);
|
||
}
|
||
|
||
// give time to other processes while this happens
|
||
while (fInfoPB.ioParam.ioResult == 1) GiveTime();
|
||
if (theErr == noErr) theErr = fInfoPB.ioParam.ioResult;
|
||
#endif
|
||
|
||
return theErr;
|
||
}
|
||
|
||
void MapOutputExtension(char *outName, OSType *creator, OSType *type)
|
||
{
|
||
*creator = '???\?';
|
||
*type = '???\?';
|
||
if (gMapResource) {
|
||
int namelen = strlen(outName);
|
||
char *p = *gMapResource;
|
||
int count = *(short *)p, i;
|
||
p += 2;
|
||
while (count--) {
|
||
int length = *p++;
|
||
for (i = 0; i < length; i++)
|
||
if (toupper(outName[namelen - length + i]) != p[i]) break;
|
||
if (i == length) {
|
||
*type = *(OSType *)&p[5];
|
||
*creator = *(OSType *)&p[9];
|
||
return;
|
||
}
|
||
p += 15;
|
||
}
|
||
}
|
||
}
|
||
|
||
OSErr FlushOutputBuffer(void)
|
||
{
|
||
Boolean buffer1 = (gOutputBufferPtr <= gOutputBufferBase + kOutputBufferSize);
|
||
static ParmBlkPtr pb, oppPB;
|
||
OSErr theErr = noErr;
|
||
|
||
// point to the current parameter block and the opposing one
|
||
pb = (buffer1) ? &gOutputPB1 : &gOutputPB2;
|
||
oppPB = (buffer1) ? &gOutputPB2 : &gOutputPB1;
|
||
|
||
// make sure that the asynchronous open of the file finished
|
||
while (gOpenOutputPB.ioParam.ioResult == 1) GiveTime();
|
||
if (gOpenOutputPB.ioParam.ioResult != noErr) return gOpenOutputPB.ioParam.ioResult;
|
||
gOutputRefNum = gOpenOutputPB.ioParam.ioRefNum;
|
||
|
||
// now set up the parameter block for the write and do it
|
||
pb->ioParam.ioRefNum = gOutputRefNum;
|
||
pb->ioParam.ioReqCount = gOutputBufferCount;
|
||
pb->ioParam.ioResult = 1;
|
||
theErr = PBWriteAsync(pb);
|
||
|
||
// reset the counts and the buffer pointers
|
||
gOutputBufferCount = 0;
|
||
gOutputBufferPtr = oppPB->ioParam.ioBuffer;
|
||
|
||
// then make sure that the previous write from the next buffer is all done and return
|
||
while (oppPB->ioParam.ioResult == 1) GiveTime();
|
||
if (oppPB->ioParam.ioResult != noErr) theErr = oppPB->ioParam.ioResult;
|
||
return theErr;
|
||
}
|
||
|
||
OSErr CloseOutputFile(FSSpecPtr theSpec)
|
||
{
|
||
OSErr theErr;
|
||
|
||
gCloseOutputPB.ioParam.ioCompletion = gGenericCompletion;
|
||
gCloseOutputPB.ioParam.ioRefNum = gOutputRefNum;
|
||
theErr = PBCloseAsync((ParmBlkPtr)&gCloseOutputPB);
|
||
if (gAborted) {
|
||
static Str255 name;
|
||
BlockMove(theSpec->name, name, *theSpec->name + 1);
|
||
while (gCloseOutputPB.ioParam.ioResult == 1) GiveTime();
|
||
gCloseOutputPB.fileParam.ioCompletion = gGenericCompletion;
|
||
gCloseOutputPB.fileParam.ioNamePtr = name;
|
||
gCloseOutputPB.fileParam.ioVRefNum = theSpec->vRefNum;
|
||
gCloseOutputPB.fileParam.ioDirID = theSpec->parID;
|
||
gCloseOutputPB.ioParam.ioResult = 1;
|
||
theErr = PBHDeleteAsync(&gCloseOutputPB);
|
||
}
|
||
return theErr;
|
||
}
|
||
|
||
void AddToQueue(FSSpec *theSpec, Handle userData)
|
||
{
|
||
odocQueuePtr odoc = (odocQueuePtr)NewPtrClear(sizeof(odocQueue)), o;
|
||
if (odoc) {
|
||
if (godocQueue) {
|
||
for (o = godocQueue; o->next; o = o->next);
|
||
if (o) o->next = odoc;
|
||
} else godocQueue = odoc;
|
||
odoc->spec = *theSpec;
|
||
odoc->data = userData;
|
||
}
|
||
|
||
}
|
||
|
||
void ProcessQueue(void)
|
||
{
|
||
odocQueuePtr o;
|
||
while (o = godocQueue) {
|
||
OpenDoc(&o->spec, true, o->data);
|
||
godocQueue = o->next;
|
||
DisposePtr((Ptr)o);
|
||
}
|
||
}
|
||
|
||
void DisableMenus(void)
|
||
{
|
||
MenuHandle theMenu = GetMHandle(kAppleNum);
|
||
DisableItem(theMenu, 1);
|
||
theMenu = GetMHandle(kFileNum);
|
||
DisableItem(theMenu, 0);
|
||
DrawMenuBar();
|
||
}
|
||
|
||
void EnableMenus(void)
|
||
{
|
||
MenuHandle theMenu = GetMHandle(kAppleNum);
|
||
EnableItem(theMenu, 1);
|
||
theMenu = GetMHandle(kFileNum);
|
||
EnableItem(theMenu, 0);
|
||
DrawMenuBar();
|
||
}
|
||
|
||
#if defined(powerc) || defined(__powerc)
|
||
pascal void GenericCompletion(ParmBlkPtr paramBlock)
|
||
#else
|
||
pascal void GenericCompletion(void)
|
||
#endif
|
||
{
|
||
}
|