home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 634.lha / ppdata_v1.0 / src.LZH / src / crunch.c next >
Encoding:
C/C++ Source or Header  |  1992-04-12  |  13.1 KB  |  505 lines

  1. /*
  2. *    crunch.c
  3. *
  4. *    Routines for crunching and decrunching files.
  5. *
  6. *    MWS 3/92.
  7. */
  8.  
  9. #include <exec/types.h>
  10. #include <intuition/intuition.h>
  11. #include <libraries/asl.h>
  12. #include <libraries/ppbase.h>
  13. #include <proto/exec.h>
  14. #include <proto/dos.h>
  15. #include <proto/intuition.h>
  16. #include <proto/asl.h>
  17. #include <proto/powerpacker.h>
  18. #include <string.h>
  19.  
  20. #include "wintext.h"
  21.  
  22. #include "prefs.h"
  23. #include "messages.h"
  24. #include "crunch.h"
  25. #include "display.h"
  26.  
  27. /***************************** STATIC PROTOTYPES ******************************/
  28.  
  29. static void FreeCrunchMem(BOOL display);
  30. static void DoFileRequest(char *hail, char *dir, char *file,
  31.               LONG flags, void (*func)(char *));
  32. static void OnLoad(char *file);
  33. static void RemExt(char *s, char *ext);
  34. static BOOL AddExt(char *s, char *ext, int destlen);
  35. static BOOL Exists(char *file);
  36. static void SetSaveFile(char *file);
  37. static void OnSave(char *file);
  38. static void OnBatch(char *file);
  39. static void OnDelete(char *file);
  40.  
  41. /***************************** WINTEXT DATA ***********************************/
  42.  
  43. static char    filelenbuf[10], decrunchedbuf[10],
  44.         statusbuf[TEXT_COLUMNS+1], progressbuf[TEXT_COLUMNS+1];
  45.  
  46.                /* next  text  lp tp pen mode width */
  47. WINTEXT wt_filename =    { NULL, NULL, 15, 0, 1, JAM2, -1 };
  48. WINTEXT wt_filelength =    { NULL, filelenbuf, 15, 1, 1, JAM2, -1 };
  49. WINTEXT wt_decrunched =    { NULL, decrunchedbuf, 15, 2, 1, JAM2, -1 };
  50. WINTEXT wt_status =     { NULL, statusbuf,  1, 4, 2, JAM2, -1 };
  51. WINTEXT wt_progress =     { NULL, progressbuf,  1, 5, 2, JAM2, -1 };
  52.  
  53. /***************************** ASL/PPLIB DATA *********************************/
  54.  
  55. extern struct Window *window;        /* asl requester attached to this */
  56. static struct FileRequester *fr;    /* for load/save/delete operations */
  57.  
  58. static struct {
  59.     UBYTE *buffer;            /* crunched/decrunched file */
  60.     LONG buflen;            /* size of crunchbuffer */
  61.     LONG crunlen;            /* size of crunched file */
  62.     BOOL saved;            /* has it been saved? */
  63.     BOOL decrunched;        /* does buffer contain decrunched file? */
  64.     LONG efficiency;        /* efficiency used in this context */
  65. } CONTEXT;
  66.  
  67. #define ERRBUF_LEN    80
  68. static char    errbuf[ERRBUF_LEN];    /* for Fault() */
  69.  
  70. #define DIR_LEN        100
  71. #define FILE_LEN    40
  72. static char    loaddir[DIR_LEN], loadfile[FILE_LEN],    /* save load/save paths */
  73.         savedir[DIR_LEN], savefile[FILE_LEN];
  74.  
  75.  
  76. #define HAILTAG    0
  77. #define DIRTAG    1
  78. #define FILETAG    2
  79. #define FLAGTAG    3    /* used for setting MULTISELECT */
  80.  
  81. struct TagItem frtags[] = {
  82.     { ASL_Hail,    NULL },
  83.     { ASL_Dir,    NULL },
  84.     { ASL_File,    NULL },
  85.     { ASL_FuncFlags,NULL },
  86.     { TAG_DONE }
  87. };
  88.  
  89. /***************************** INITIATION/FREEING ROUTINES ********************/
  90.  
  91. BOOL IsBufferSaved()    /* yes or no? */
  92. {
  93.     if (CONTEXT.buffer && !CONTEXT.saved)    /* haven't saved work */
  94.         return FALSE;
  95.     return TRUE;
  96. }
  97.  
  98. static void FreeCrunchMem(BOOL display)    /* free buffer memory, set pointer to NULL */
  99. {                    /* if display == TRUE, update WINTEXTS to */
  100.                     /* indicate no file now loaded */
  101.  
  102.     if (CONTEXT.buffer) FreeMem(CONTEXT.buffer, CONTEXT.buflen);
  103.     CONTEXT.buffer = NULL;
  104.  
  105.     if (display)    /* set wintexts to blanks (except status line) */
  106.     {
  107.         RenderWinTextsFmt(&wtinfo, &wt_filename, NULL);
  108.         RenderWinTextsFmt(&wtinfo, &wt_filelength, NULL);
  109.         RenderWinTextsFmt(&wtinfo, &wt_decrunched, NULL);
  110.         RenderWinTextsFmt(&wtinfo, &wt_progress, NULL);
  111.     }
  112. }
  113.  
  114. BOOL InitCrunch()    /* initialize data for crunch routines */
  115. {
  116.     struct TagItem ti[2];
  117.  
  118.     ti[0].ti_Tag = ASL_Window;
  119.     ti[0].ti_Data = (LONG)window;
  120.     ti[1].ti_Tag = TAG_DONE;
  121.  
  122.     if (fr = AllocAslRequest(ASL_FileRequest, ti))
  123.         return TRUE;
  124.     return FALSE;
  125. }
  126.  
  127. void FinishCrunch()    /* free memory/clean up crunch stuff */
  128. {
  129.     FreeCrunchMem(FALSE);
  130.     if (fr) FreeAslRequest(fr);
  131. }
  132.  
  133. /***************************** GENERAL FILEREQUEST ROUTINE ********************/
  134.  
  135. static void DoFileRequest(char *hail, char *dir, char *file, LONG flags,
  136.              void (*func)(char *))
  137. {
  138.     BPTR oldcd, newcd;
  139.  
  140.     frtags[HAILTAG].ti_Data = (LONG)hail;
  141.     frtags[DIRTAG].ti_Data = (LONG)dir;
  142.     frtags[FILETAG].ti_Data = (LONG)file;
  143.     frtags[FLAGTAG].ti_Data = flags;
  144.  
  145.     if (AslRequest(fr, frtags))    /* user didn't CANCEL */
  146.     {
  147.         if (flags & FILF_MULTISELECT)    /* batch mode */
  148.         {
  149.             LONG argc = fr->rf_NumArgs;
  150.             struct WBArg *argv = fr->rf_ArgList;
  151.  
  152.             oldcd = CurrentDir(argv->wa_Lock);  /* get current dir */
  153.             while (argc--)    /* skip through arglist */
  154.             {
  155.                 CurrentDir(argv->wa_Lock);
  156.                 func(argv->wa_Name);
  157.                 argv++;
  158.             }
  159.             CurrentDir(oldcd);
  160.         }
  161.         else if (newcd = Lock(fr->rf_Dir,ACCESS_READ)) /* get lock on directory */
  162.         {
  163.             oldcd = CurrentDir(newcd);    /* move to file's directory */
  164.  
  165.             if (file) strncpy(file, fr->rf_File, FILE_LEN-1);
  166.             if (dir) strncpy(dir, fr->rf_Dir, DIR_LEN-1);
  167.  
  168.             func(fr->rf_File);        /* visit file */
  169.  
  170.             (void)CurrentDir(oldcd);    /* restore current dir */
  171.             UnLock(newcd);
  172.         }
  173.         else Message("Couldn't lock directory %s\n", dir);
  174.     }
  175. }
  176.  
  177. /***************************** LOAD ROUTINES **********************************/
  178. /* TODO: Add handling of encrypted files? How many use this (I don't)?          */
  179.  
  180. BOOL __stdargs __saveds ProgressIndicator(ULONG sofar, ULONG crunlen, ULONG totlen)
  181. {
  182.     struct IntuiMessage *msg;
  183.  
  184.     RenderWinTextsFmt(&wtinfo, &wt_progress, "%ld%% crunched. (%ld%% gain)",
  185.          (sofar * 100) / totlen, 100 - (100 * crunlen) / sofar);
  186.  
  187.     while (msg = (struct IntuiMessage *)GetMsg(window->UserPort))
  188.     {
  189.         if (msg->Class == MENUPICK)
  190.         {
  191.             if ((MENUNUM(msg->Code) == 0) && (ITEMNUM(msg->Code) == 0))
  192.                 return FALSE;
  193.         }
  194.         else if (msg->Class == CLOSEWINDOW)
  195.             return FALSE;
  196.     }
  197.  
  198.     return TRUE;
  199. }
  200.  
  201. #define PPID 0x50503230        /* 'PP20' */
  202.  
  203. LONG AlreadyCrunched(char *file)    /* only goes on 1st 2 chars... */
  204. {                    /* doesn't recognise encrypted files yet */
  205.     BPTR fh;
  206.     ULONG ppid;
  207.     LONG size = 0;    /* file size, or zero if not crunched */
  208.  
  209.     if (fh = Open(file, MODE_OLDFILE))
  210.     {
  211.         if (Read(fh, &ppid, sizeof(ppid)) == sizeof(ppid))
  212.         {
  213.             if (ppid == PPID)    /* get old length */
  214.             {
  215.                 struct FileInfoBlock __aligned fib;
  216.  
  217.                 if (ExamineFH(fh, &fib))
  218.                     size = fib.fib_Size;
  219.             }
  220.         }
  221.         Close(fh);
  222.     }
  223.     /* open/read/examine errors will be picked up later (by ppLoadData) */ 
  224.  
  225.     return size;
  226. }
  227.  
  228. static void OnLoad(char *file)    /* main load and (de)crunch routine */
  229. {
  230.     APTR crunchinfo;            /* crunch info for current context */
  231.     LONG oldlen, gainbytes;
  232.     UWORD err;
  233.     BOOL decrunchonly = FALSE;
  234.  
  235.     if (oldlen = AlreadyCrunched(file))
  236.     {                  /*    1        2       0    */ 
  237.         if (prefs.control == QUERY)
  238.             err = MultiRequest("Decrunch|Recrunch|Cancel", 
  239.                     "%s is already crunched.\nSelect action:", file);
  240.         else err = (prefs.control + 1)%3;
  241.  
  242.         if (err == 1)    /* Decrunch */
  243.         {
  244.             RenderWinTextsFmt(&wtinfo, &wt_filelength, "%ld", oldlen);
  245.             decrunchonly = TRUE;
  246.         }
  247.         else if (err == 0) /* Cancel */
  248.         {
  249.             RenderWinTextsFmt(&wtinfo, &wt_status,
  250.                       "Skipping file %.20s", file);
  251.             return;
  252.         }
  253.         /* else err == 2 --> recrunch, so fall through */
  254.     }
  255.  
  256.     wt_filename.text = file;
  257.     RenderWinTexts(&wtinfo, &wt_filename);
  258.     RenderWinTextsFmt(&wtinfo, &wt_status, "Loading file %.20s", file);
  259.  
  260.     if (err = ppLoadData(file, prefs.color, 0L,
  261.                  &CONTEXT.buffer, &CONTEXT.buflen, (void *)(-1L)))
  262.     {
  263.         CONTEXT.buffer = NULL;
  264.         RenderWinTextsFmt(&wtinfo, &wt_status, NULL);
  265.         Message("Error loading file %s:\n%s", file, ppErrorMessage(err));
  266.     }
  267.     else if (decrunchonly)    /* Done! update display */
  268.     {
  269.         RenderWinTextsFmt(&wtinfo, &wt_decrunched, "%ld", CONTEXT.buflen);
  270.         RenderWinTextsFmt(&wtinfo, &wt_status, "File decrunched");
  271.  
  272.         CONTEXT.saved = FALSE;
  273.         CONTEXT.decrunched = TRUE;    /* buffer contains decrunched file */
  274.     }
  275.     else    /* uncrunched file loaded: proceed with crunching */ 
  276.     {
  277.         RenderWinTextsFmt(&wtinfo, &wt_filelength, "%ld", CONTEXT.buflen);
  278.  
  279.         crunchinfo = ppAllocCrunchInfo( prefs.efficiency,
  280.                             prefs.speedup,
  281.                             ProgressIndicator, NULL);
  282.  
  283.         if (crunchinfo)        /* allocation okay */
  284.         {
  285.             CONTEXT.efficiency = prefs.efficiency;
  286.             RenderWinTextsFmt(&wtinfo, &wt_status, "Crunching file %.30s", file);
  287.  
  288.             SetPPDataMenu(ABORTMENU);
  289.             CONTEXT.crunlen = ppCrunchBuffer(crunchinfo,
  290.                              CONTEXT.buffer, 
  291.                              CONTEXT.buflen);
  292.             SetPPDataMenu(MAINMENU);
  293.  
  294.             if (CONTEXT.crunlen == PP_CRUNCHABORTED)
  295.             {
  296.                 FreeCrunchMem(TRUE);                
  297.                 RenderWinTextsFmt(&wtinfo, &wt_status, "Crunch aborted");
  298.             }
  299.             else if (CONTEXT.crunlen == PP_BUFFEROVERFLOW)
  300.             {
  301.                 FreeCrunchMem(TRUE);
  302.                 RenderWinTextsFmt(&wtinfo, &wt_status, "Buffer overflow");
  303.             }
  304.             else    /* success! Update wintexts */
  305.             {
  306.                 gainbytes = CONTEXT.buflen-CONTEXT.crunlen;
  307.  
  308.                 RenderWinTextsFmt(&wtinfo, &wt_decrunched, "%ld", CONTEXT.crunlen);
  309.                 RenderWinTextsFmt(&wtinfo, &wt_status, "File crunched");
  310.                 RenderWinTextsFmt(&wtinfo, &wt_progress, 
  311.                           "Gained %ld%% (%ld bytes)",
  312.                           (gainbytes * 100) / CONTEXT.buflen,
  313.                           gainbytes);
  314.  
  315.                 CONTEXT.saved = FALSE;
  316.                 CONTEXT.decrunched = FALSE; /* buffer contains crunched file */
  317.                 /* user can now save buffer at his/her leisure */
  318.             }
  319.  
  320.             ppFreeCrunchInfo(crunchinfo);
  321.  
  322.         } /* crunchinfo allocated okay */
  323.  
  324.     } /* no error on load */
  325. }
  326.  
  327. void LoadRequest()    /* Load a file; action depends on what file is */ 
  328. {
  329.     RenderWinTextsFmt(&wtinfo, &wt_status, NULL);    /* clear status */
  330.  
  331.     if (IsBufferSaved() ||
  332.         Confirm("Current buffer unsaved.\nContinue with load?"))
  333.     {
  334.         FreeCrunchMem(TRUE);    /* free current contents */
  335.   
  336.         DoFileRequest("Load File...", loaddir, loadfile, 0, OnLoad);
  337.     }
  338. }
  339.             
  340. /***************************** SAVE ROUTINES **********************************/
  341.  
  342. static void RemExt(char *s, char *ext)    /* remove extension if it exists */
  343. {                    /* ext SHOULD contain '.' */
  344.     char *t;
  345.  
  346.     t = &s[strlen(s)-2];        /* t points to last char in s */
  347.  
  348.     while ((*t != '.') && (t > s))        /* find (last) extension */
  349.         t--;
  350.  
  351.     if (*t == '.' && !stricmp(t,ext))    /* has given ext */
  352.         *t = '\0';
  353. }
  354.  
  355. static BOOL AddExt(char *s, char *ext, int destlen)    /* add extension supplied if */
  356. {                            /* it's not already on */
  357.     int l;                        /* ext SHOULD contain '.' */
  358.     char *t;
  359.  
  360.     l = strlen(s);        /* length of string */
  361.     t = &s[l-2];        /* t points to last char in s */
  362.  
  363.     while ((*t != '.') && (t > s))        /* find (last) extension */
  364.         t--;
  365.  
  366.     if (*t == '.' && !stricmp(t,ext))    /* already has correct ext */
  367.         return TRUE;
  368.  
  369.     if ((l+strlen(ext)) < destlen)        /* space to append ext? */
  370.     {
  371.         strcat(s,ext);
  372.         return TRUE;
  373.     }
  374.  
  375.     return FALSE;        /* insufficient space */
  376. }
  377.  
  378. static BOOL Exists(char *file)            /* does file exist? */
  379. {
  380.     BPTR lock;
  381.  
  382.     if (lock = Lock(file, ACCESS_READ))
  383.     {
  384.         UnLock(lock);
  385.         return TRUE;
  386.     }
  387.     return FALSE;
  388. }
  389.  
  390. static void OnSave(char *file)        /* save file from requester */
  391. {
  392.     BPTR fh;
  393.     LONG amount;
  394.  
  395.     /* TODO: Error messages to get error string from Fault() */
  396.  
  397.     if (!prefs.overwrite && Exists(file))
  398.         if (!Confirm("Overwrite file %s?", file))
  399.             return;
  400.  
  401.     amount = CONTEXT.decrunched ? CONTEXT.buflen : CONTEXT.crunlen;
  402.  
  403.     if (fh = Open(file, MODE_NEWFILE))
  404.     {
  405.         if (CONTEXT.decrunched || ppWriteDataHeader(fh, CONTEXT.efficiency, FALSE, 0))
  406.         {
  407.             if (Write(fh, CONTEXT.buffer, amount) == amount)
  408.             {
  409.                 RenderWinTextsFmt(&wtinfo, &wt_status, "Saved to %s", savefile);
  410.                 CONTEXT.saved = TRUE;
  411.             }
  412.             else Message("Error writing to file %s", file);
  413.         }
  414.         else Message("Can't write data header to %s", file);
  415.  
  416.         Close(fh);
  417.     }
  418.     else Message("Can't open file %s", file);
  419. }
  420.  
  421. static void SetSaveFile(char *name)    /* adds or removes '.pp' depending */
  422. {                    /* on CONTEXT and preferences */
  423.     strcpy(savefile, name);
  424.     if (prefs.suffix)
  425.         if (CONTEXT.decrunched)        /* remove possible ".pp" */
  426.             RemExt(savefile, ".pp");
  427.         else
  428.             AddExt(savefile, ".pp", FILE_LEN);
  429. }
  430.  
  431. void SaveRequest()    /* Save current crunch buffer to file */
  432. {
  433.     RenderWinTextsFmt(&wtinfo, &wt_status, NULL);    /* clear status */
  434.     RenderWinTextsFmt(&wtinfo, &wt_progress, NULL);    /* and progress */
  435.  
  436.     if (CONTEXT.buffer)    /* something to save */
  437.     {
  438.         SetSaveFile(loadfile);
  439.  
  440.         DoFileRequest("Save As...", savedir, savefile, FILF_SAVE, OnSave);
  441.     }
  442.     else Message("Nothing to save!");
  443. }
  444.  
  445. /***************************** BATCH ROUTINES *********************************/
  446.  
  447. static BOOL savepath;    /* successfully chosen save path? */
  448.  
  449. static void OnBatch(char *file)    /* process file and save to savedir */
  450. {
  451.     FreeCrunchMem(TRUE);    
  452.     OnLoad(file);        /* do what needs to be done to file */
  453.     if (CONTEXT.buffer)    /* something to save */
  454.     {
  455.         BPTR oldcd, newcd;
  456.  
  457.         if (newcd = Lock(savedir, ACCESS_READ))
  458.         {
  459.             oldcd = CurrentDir(newcd);
  460.             SetSaveFile(file);
  461.             OnSave(savefile);
  462.             CurrentDir(oldcd);
  463.         }
  464.         else Message("Couldn't lock directory %s\n", savedir);
  465.     }
  466. }
  467.  
  468. static void ObtainSavePath(char *file)    /* note that save path was chosen */
  469. {
  470.     savepath = TRUE;
  471. }
  472.  
  473. void BatchRequest(void)        /* like the name says... */
  474. {
  475.     if (IsBufferSaved() ||
  476.         Confirm("Current buffer unsaved.\nProceed with batch?"))
  477.     {
  478.         savepath = FALSE;
  479.         DoFileRequest("Select Save Path...", savedir, NULL,
  480.                   FILF_SAVE, ObtainSavePath);
  481.         if (savepath)
  482.         {
  483.             DoFileRequest("Select files to process",
  484.                       loaddir, loadfile, FILF_MULTISELECT, OnBatch);
  485.         }
  486.     }
  487. }
  488.  
  489. /***************************** DELETE ROUTINES ********************************/
  490.  
  491. static void OnDelete(char *file)    /* delete given file */
  492. {
  493.     if (Confirm("Really delete %s?", file))    /* confirm with user */
  494.         if (!DeleteFile(file))        /* do deletion */
  495.         {
  496.             Fault(IoErr(), " - ", errbuf, ERRBUF_LEN);
  497.             Message("Couldn't delete file %s\n%s", file, errbuf); 
  498.         }            
  499. }
  500.  
  501. void DeleteRequest()    /* Delete a file */
  502. {
  503.     DoFileRequest("Delete File...", loaddir, loadfile, 0, OnDelete);
  504. }
  505.