home *** CD-ROM | disk | FTP | other *** search
- /*
- * crunch.c
- *
- * Routines for crunching and decrunching files.
- *
- * MWS 3/92.
- */
-
- #include <exec/types.h>
- #include <intuition/intuition.h>
- #include <libraries/asl.h>
- #include <libraries/ppbase.h>
- #include <proto/exec.h>
- #include <proto/dos.h>
- #include <proto/intuition.h>
- #include <proto/asl.h>
- #include <proto/powerpacker.h>
- #include <string.h>
-
- #include "wintext.h"
-
- #include "prefs.h"
- #include "messages.h"
- #include "crunch.h"
- #include "display.h"
-
- /***************************** STATIC PROTOTYPES ******************************/
-
- static void FreeCrunchMem(BOOL display);
- static void DoFileRequest(char *hail, char *dir, char *file,
- LONG flags, void (*func)(char *));
- static void OnLoad(char *file);
- static void RemExt(char *s, char *ext);
- static BOOL AddExt(char *s, char *ext, int destlen);
- static BOOL Exists(char *file);
- static void SetSaveFile(char *file);
- static void OnSave(char *file);
- static void OnBatch(char *file);
- static void OnDelete(char *file);
-
- /***************************** WINTEXT DATA ***********************************/
-
- static char filelenbuf[10], decrunchedbuf[10],
- statusbuf[TEXT_COLUMNS+1], progressbuf[TEXT_COLUMNS+1];
-
- /* next text lp tp pen mode width */
- WINTEXT wt_filename = { NULL, NULL, 15, 0, 1, JAM2, -1 };
- WINTEXT wt_filelength = { NULL, filelenbuf, 15, 1, 1, JAM2, -1 };
- WINTEXT wt_decrunched = { NULL, decrunchedbuf, 15, 2, 1, JAM2, -1 };
- WINTEXT wt_status = { NULL, statusbuf, 1, 4, 2, JAM2, -1 };
- WINTEXT wt_progress = { NULL, progressbuf, 1, 5, 2, JAM2, -1 };
-
- /***************************** ASL/PPLIB DATA *********************************/
-
- extern struct Window *window; /* asl requester attached to this */
- static struct FileRequester *fr; /* for load/save/delete operations */
-
- static struct {
- UBYTE *buffer; /* crunched/decrunched file */
- LONG buflen; /* size of crunchbuffer */
- LONG crunlen; /* size of crunched file */
- BOOL saved; /* has it been saved? */
- BOOL decrunched; /* does buffer contain decrunched file? */
- LONG efficiency; /* efficiency used in this context */
- } CONTEXT;
-
- #define ERRBUF_LEN 80
- static char errbuf[ERRBUF_LEN]; /* for Fault() */
-
- #define DIR_LEN 100
- #define FILE_LEN 40
- static char loaddir[DIR_LEN], loadfile[FILE_LEN], /* save load/save paths */
- savedir[DIR_LEN], savefile[FILE_LEN];
-
-
- #define HAILTAG 0
- #define DIRTAG 1
- #define FILETAG 2
- #define FLAGTAG 3 /* used for setting MULTISELECT */
-
- struct TagItem frtags[] = {
- { ASL_Hail, NULL },
- { ASL_Dir, NULL },
- { ASL_File, NULL },
- { ASL_FuncFlags,NULL },
- { TAG_DONE }
- };
-
- /***************************** INITIATION/FREEING ROUTINES ********************/
-
- BOOL IsBufferSaved() /* yes or no? */
- {
- if (CONTEXT.buffer && !CONTEXT.saved) /* haven't saved work */
- return FALSE;
- return TRUE;
- }
-
- static void FreeCrunchMem(BOOL display) /* free buffer memory, set pointer to NULL */
- { /* if display == TRUE, update WINTEXTS to */
- /* indicate no file now loaded */
-
- if (CONTEXT.buffer) FreeMem(CONTEXT.buffer, CONTEXT.buflen);
- CONTEXT.buffer = NULL;
-
- if (display) /* set wintexts to blanks (except status line) */
- {
- RenderWinTextsFmt(&wtinfo, &wt_filename, NULL);
- RenderWinTextsFmt(&wtinfo, &wt_filelength, NULL);
- RenderWinTextsFmt(&wtinfo, &wt_decrunched, NULL);
- RenderWinTextsFmt(&wtinfo, &wt_progress, NULL);
- }
- }
-
- BOOL InitCrunch() /* initialize data for crunch routines */
- {
- struct TagItem ti[2];
-
- ti[0].ti_Tag = ASL_Window;
- ti[0].ti_Data = (LONG)window;
- ti[1].ti_Tag = TAG_DONE;
-
- if (fr = AllocAslRequest(ASL_FileRequest, ti))
- return TRUE;
- return FALSE;
- }
-
- void FinishCrunch() /* free memory/clean up crunch stuff */
- {
- FreeCrunchMem(FALSE);
- if (fr) FreeAslRequest(fr);
- }
-
- /***************************** GENERAL FILEREQUEST ROUTINE ********************/
-
- static void DoFileRequest(char *hail, char *dir, char *file, LONG flags,
- void (*func)(char *))
- {
- BPTR oldcd, newcd;
-
- frtags[HAILTAG].ti_Data = (LONG)hail;
- frtags[DIRTAG].ti_Data = (LONG)dir;
- frtags[FILETAG].ti_Data = (LONG)file;
- frtags[FLAGTAG].ti_Data = flags;
-
- if (AslRequest(fr, frtags)) /* user didn't CANCEL */
- {
- if (flags & FILF_MULTISELECT) /* batch mode */
- {
- LONG argc = fr->rf_NumArgs;
- struct WBArg *argv = fr->rf_ArgList;
-
- oldcd = CurrentDir(argv->wa_Lock); /* get current dir */
- while (argc--) /* skip through arglist */
- {
- CurrentDir(argv->wa_Lock);
- func(argv->wa_Name);
- argv++;
- }
- CurrentDir(oldcd);
- }
- else if (newcd = Lock(fr->rf_Dir,ACCESS_READ)) /* get lock on directory */
- {
- oldcd = CurrentDir(newcd); /* move to file's directory */
-
- if (file) strncpy(file, fr->rf_File, FILE_LEN-1);
- if (dir) strncpy(dir, fr->rf_Dir, DIR_LEN-1);
-
- func(fr->rf_File); /* visit file */
-
- (void)CurrentDir(oldcd); /* restore current dir */
- UnLock(newcd);
- }
- else Message("Couldn't lock directory %s\n", dir);
- }
- }
-
- /***************************** LOAD ROUTINES **********************************/
- /* TODO: Add handling of encrypted files? How many use this (I don't)? */
-
- BOOL __stdargs __saveds ProgressIndicator(ULONG sofar, ULONG crunlen, ULONG totlen)
- {
- struct IntuiMessage *msg;
-
- RenderWinTextsFmt(&wtinfo, &wt_progress, "%ld%% crunched. (%ld%% gain)",
- (sofar * 100) / totlen, 100 - (100 * crunlen) / sofar);
-
- while (msg = (struct IntuiMessage *)GetMsg(window->UserPort))
- {
- if (msg->Class == MENUPICK)
- {
- if ((MENUNUM(msg->Code) == 0) && (ITEMNUM(msg->Code) == 0))
- return FALSE;
- }
- else if (msg->Class == CLOSEWINDOW)
- return FALSE;
- }
-
- return TRUE;
- }
-
- #define PPID 0x50503230 /* 'PP20' */
-
- LONG AlreadyCrunched(char *file) /* only goes on 1st 2 chars... */
- { /* doesn't recognise encrypted files yet */
- BPTR fh;
- ULONG ppid;
- LONG size = 0; /* file size, or zero if not crunched */
-
- if (fh = Open(file, MODE_OLDFILE))
- {
- if (Read(fh, &ppid, sizeof(ppid)) == sizeof(ppid))
- {
- if (ppid == PPID) /* get old length */
- {
- struct FileInfoBlock __aligned fib;
-
- if (ExamineFH(fh, &fib))
- size = fib.fib_Size;
- }
- }
- Close(fh);
- }
- /* open/read/examine errors will be picked up later (by ppLoadData) */
-
- return size;
- }
-
- static void OnLoad(char *file) /* main load and (de)crunch routine */
- {
- APTR crunchinfo; /* crunch info for current context */
- LONG oldlen, gainbytes;
- UWORD err;
- BOOL decrunchonly = FALSE;
-
- if (oldlen = AlreadyCrunched(file))
- { /* 1 2 0 */
- if (prefs.control == QUERY)
- err = MultiRequest("Decrunch|Recrunch|Cancel",
- "%s is already crunched.\nSelect action:", file);
- else err = (prefs.control + 1)%3;
-
- if (err == 1) /* Decrunch */
- {
- RenderWinTextsFmt(&wtinfo, &wt_filelength, "%ld", oldlen);
- decrunchonly = TRUE;
- }
- else if (err == 0) /* Cancel */
- {
- RenderWinTextsFmt(&wtinfo, &wt_status,
- "Skipping file %.20s", file);
- return;
- }
- /* else err == 2 --> recrunch, so fall through */
- }
-
- wt_filename.text = file;
- RenderWinTexts(&wtinfo, &wt_filename);
- RenderWinTextsFmt(&wtinfo, &wt_status, "Loading file %.20s", file);
-
- if (err = ppLoadData(file, prefs.color, 0L,
- &CONTEXT.buffer, &CONTEXT.buflen, (void *)(-1L)))
- {
- CONTEXT.buffer = NULL;
- RenderWinTextsFmt(&wtinfo, &wt_status, NULL);
- Message("Error loading file %s:\n%s", file, ppErrorMessage(err));
- }
- else if (decrunchonly) /* Done! update display */
- {
- RenderWinTextsFmt(&wtinfo, &wt_decrunched, "%ld", CONTEXT.buflen);
- RenderWinTextsFmt(&wtinfo, &wt_status, "File decrunched");
-
- CONTEXT.saved = FALSE;
- CONTEXT.decrunched = TRUE; /* buffer contains decrunched file */
- }
- else /* uncrunched file loaded: proceed with crunching */
- {
- RenderWinTextsFmt(&wtinfo, &wt_filelength, "%ld", CONTEXT.buflen);
-
- crunchinfo = ppAllocCrunchInfo( prefs.efficiency,
- prefs.speedup,
- ProgressIndicator, NULL);
-
- if (crunchinfo) /* allocation okay */
- {
- CONTEXT.efficiency = prefs.efficiency;
- RenderWinTextsFmt(&wtinfo, &wt_status, "Crunching file %.30s", file);
-
- SetPPDataMenu(ABORTMENU);
- CONTEXT.crunlen = ppCrunchBuffer(crunchinfo,
- CONTEXT.buffer,
- CONTEXT.buflen);
- SetPPDataMenu(MAINMENU);
-
- if (CONTEXT.crunlen == PP_CRUNCHABORTED)
- {
- FreeCrunchMem(TRUE);
- RenderWinTextsFmt(&wtinfo, &wt_status, "Crunch aborted");
- }
- else if (CONTEXT.crunlen == PP_BUFFEROVERFLOW)
- {
- FreeCrunchMem(TRUE);
- RenderWinTextsFmt(&wtinfo, &wt_status, "Buffer overflow");
- }
- else /* success! Update wintexts */
- {
- gainbytes = CONTEXT.buflen-CONTEXT.crunlen;
-
- RenderWinTextsFmt(&wtinfo, &wt_decrunched, "%ld", CONTEXT.crunlen);
- RenderWinTextsFmt(&wtinfo, &wt_status, "File crunched");
- RenderWinTextsFmt(&wtinfo, &wt_progress,
- "Gained %ld%% (%ld bytes)",
- (gainbytes * 100) / CONTEXT.buflen,
- gainbytes);
-
- CONTEXT.saved = FALSE;
- CONTEXT.decrunched = FALSE; /* buffer contains crunched file */
- /* user can now save buffer at his/her leisure */
- }
-
- ppFreeCrunchInfo(crunchinfo);
-
- } /* crunchinfo allocated okay */
-
- } /* no error on load */
- }
-
- void LoadRequest() /* Load a file; action depends on what file is */
- {
- RenderWinTextsFmt(&wtinfo, &wt_status, NULL); /* clear status */
-
- if (IsBufferSaved() ||
- Confirm("Current buffer unsaved.\nContinue with load?"))
- {
- FreeCrunchMem(TRUE); /* free current contents */
-
- DoFileRequest("Load File...", loaddir, loadfile, 0, OnLoad);
- }
- }
-
- /***************************** SAVE ROUTINES **********************************/
-
- static void RemExt(char *s, char *ext) /* remove extension if it exists */
- { /* ext SHOULD contain '.' */
- char *t;
-
- t = &s[strlen(s)-2]; /* t points to last char in s */
-
- while ((*t != '.') && (t > s)) /* find (last) extension */
- t--;
-
- if (*t == '.' && !stricmp(t,ext)) /* has given ext */
- *t = '\0';
- }
-
- static BOOL AddExt(char *s, char *ext, int destlen) /* add extension supplied if */
- { /* it's not already on */
- int l; /* ext SHOULD contain '.' */
- char *t;
-
- l = strlen(s); /* length of string */
- t = &s[l-2]; /* t points to last char in s */
-
- while ((*t != '.') && (t > s)) /* find (last) extension */
- t--;
-
- if (*t == '.' && !stricmp(t,ext)) /* already has correct ext */
- return TRUE;
-
- if ((l+strlen(ext)) < destlen) /* space to append ext? */
- {
- strcat(s,ext);
- return TRUE;
- }
-
- return FALSE; /* insufficient space */
- }
-
- static BOOL Exists(char *file) /* does file exist? */
- {
- BPTR lock;
-
- if (lock = Lock(file, ACCESS_READ))
- {
- UnLock(lock);
- return TRUE;
- }
- return FALSE;
- }
-
- static void OnSave(char *file) /* save file from requester */
- {
- BPTR fh;
- LONG amount;
-
- /* TODO: Error messages to get error string from Fault() */
-
- if (!prefs.overwrite && Exists(file))
- if (!Confirm("Overwrite file %s?", file))
- return;
-
- amount = CONTEXT.decrunched ? CONTEXT.buflen : CONTEXT.crunlen;
-
- if (fh = Open(file, MODE_NEWFILE))
- {
- if (CONTEXT.decrunched || ppWriteDataHeader(fh, CONTEXT.efficiency, FALSE, 0))
- {
- if (Write(fh, CONTEXT.buffer, amount) == amount)
- {
- RenderWinTextsFmt(&wtinfo, &wt_status, "Saved to %s", savefile);
- CONTEXT.saved = TRUE;
- }
- else Message("Error writing to file %s", file);
- }
- else Message("Can't write data header to %s", file);
-
- Close(fh);
- }
- else Message("Can't open file %s", file);
- }
-
- static void SetSaveFile(char *name) /* adds or removes '.pp' depending */
- { /* on CONTEXT and preferences */
- strcpy(savefile, name);
- if (prefs.suffix)
- if (CONTEXT.decrunched) /* remove possible ".pp" */
- RemExt(savefile, ".pp");
- else
- AddExt(savefile, ".pp", FILE_LEN);
- }
-
- void SaveRequest() /* Save current crunch buffer to file */
- {
- RenderWinTextsFmt(&wtinfo, &wt_status, NULL); /* clear status */
- RenderWinTextsFmt(&wtinfo, &wt_progress, NULL); /* and progress */
-
- if (CONTEXT.buffer) /* something to save */
- {
- SetSaveFile(loadfile);
-
- DoFileRequest("Save As...", savedir, savefile, FILF_SAVE, OnSave);
- }
- else Message("Nothing to save!");
- }
-
- /***************************** BATCH ROUTINES *********************************/
-
- static BOOL savepath; /* successfully chosen save path? */
-
- static void OnBatch(char *file) /* process file and save to savedir */
- {
- FreeCrunchMem(TRUE);
- OnLoad(file); /* do what needs to be done to file */
- if (CONTEXT.buffer) /* something to save */
- {
- BPTR oldcd, newcd;
-
- if (newcd = Lock(savedir, ACCESS_READ))
- {
- oldcd = CurrentDir(newcd);
- SetSaveFile(file);
- OnSave(savefile);
- CurrentDir(oldcd);
- }
- else Message("Couldn't lock directory %s\n", savedir);
- }
- }
-
- static void ObtainSavePath(char *file) /* note that save path was chosen */
- {
- savepath = TRUE;
- }
-
- void BatchRequest(void) /* like the name says... */
- {
- if (IsBufferSaved() ||
- Confirm("Current buffer unsaved.\nProceed with batch?"))
- {
- savepath = FALSE;
- DoFileRequest("Select Save Path...", savedir, NULL,
- FILF_SAVE, ObtainSavePath);
- if (savepath)
- {
- DoFileRequest("Select files to process",
- loaddir, loadfile, FILF_MULTISELECT, OnBatch);
- }
- }
- }
-
- /***************************** DELETE ROUTINES ********************************/
-
- static void OnDelete(char *file) /* delete given file */
- {
- if (Confirm("Really delete %s?", file)) /* confirm with user */
- if (!DeleteFile(file)) /* do deletion */
- {
- Fault(IoErr(), " - ", errbuf, ERRBUF_LEN);
- Message("Couldn't delete file %s\n%s", file, errbuf);
- }
- }
-
- void DeleteRequest() /* Delete a file */
- {
- DoFileRequest("Delete File...", loaddir, loadfile, 0, OnDelete);
- }
-