home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 3 / TheARMClub_PDCD3.iso / hensa / programming / desklib / examples / DeskLib / Examples / Widget5 / !Widget5 / c / LoadSave < prev    next >
Encoding:
Text File  |  1995-05-10  |  26.1 KB  |  1,133 lines

  1. /************************************************************************
  2.  *                                                                      *
  3.  *        File: LoadSave.c                                              *
  4.  *                                                                      *
  5.  *     Purpose: Provides routines to load and save images as Widget5    *
  6.  *              (text), Widget4 (simple byte per pixel) and Sprite      *
  7.  *              format.                                                 *
  8.  *                                                                      *
  9.  ************************************************************************/
  10.  
  11. #include "DeskLib:WimpSWIs.h"          /* Low-level WIMP commands         */
  12. #include "DeskLib:Window.h"            /* Window handling automation      */
  13. #include "DeskLib:Core.h"              /* usefull core functions          */
  14. #include "DeskLib:Error.h"             /* Error despatcher                */
  15. #include "DeskLib:Event.h"             /* Event despatcher                */
  16. #include "DeskLib:EventMsg.h"          /* Wimp Message event dispatcher   */
  17. #include "DeskLib:File.h"              /* Low level file handling         */
  18. #include "DeskLib:Msgs.h"              /* Message translation code        */
  19. #include "DeskLib:Resource.h"          /* Handles finding resource files  */
  20. #include "DeskLib:Sound.h"             /* Beep!                           */
  21. #include "DeskLib:Template.h"          /* Template loading and caching    */
  22. #include "DeskLib:Icon.h"              /* Icon handling automation        */
  23. #include "DeskLib:Screen.h"            /* Caching screen info             */
  24. #include "DeskLib:Sprite.h"            /* Sprite handling routines        */
  25. #include "DeskLib:File.h"              /* OS file IO                      */
  26. #include "DeskLib:KeyCodes.h"          /* Codes for wimp returned keys    */
  27. #include "DeskLib:Hourglass.h"         /* control hourglass               */
  28.  
  29. #include "HackLib:flex.h"              /* Flexable malloc                 */
  30.  
  31. #include "ATrans.h"                    /* My load/save library            */
  32.  
  33. #include "kernel.h"                    /* clib kernel functions           */
  34. #include "MySWIs.h"                    /* SWI no defs                     */
  35. #include "LoadSave.h"
  36. #include "SpriteWin.h"
  37. #include "Misc.h"
  38. #include "CheckBanks.h"
  39. #include "Configure.h"
  40.  
  41. #include <stdio.h>
  42. #include <stdlib.h>
  43. #include <string.h>
  44.  
  45. extern window_handle db;
  46.  
  47. /* icon numbers for image bank radios */
  48. #define image_MIN 11
  49. #define image_MAX 16
  50.  
  51. /* image bank number that is being saved */
  52. static int saveimagebank = -1;
  53. /* number of greys in saved image */
  54. static int savenumbergreys = 0;
  55.  
  56. typedef struct {
  57.    iconrange_block range;
  58.    spritewin_block *image;
  59. } tempimage_block;
  60.  
  61. void load_widget5(char *filename);
  62. void load_widget4(char *filename);
  63. void load_sprite(char *filename);
  64. void load_abort1(file_handle channel, tempimage_block *block);
  65. void load_abort2(file_handle channel, tempimage_block *block);
  66. void save_widget5(char *filename, int imageno, int numbergreys);
  67. void save_widget4(char *filename, int imageno);
  68. void save_sprite(char *filename, int imageno);
  69. tempimage_block *open_load(char *filename, int filetype);
  70. void close_load(tempimage_block *block, BOOL ok);
  71. static BOOL Close_load(event_pollblock *event, void *reference);
  72. static BOOL Click_load(event_pollblock *event, void *reference);
  73. BOOL write_newline(file_handle channel);
  74. BOOL write_space(file_handle channel);
  75. BOOL write_text(file_handle channel, char *text, int padto);
  76. BOOL read_charint(file_handle channel, int *integer);
  77. void NoLoad(char *err);
  78. void NoMemLoad(void);
  79. void NoSave(char *err);
  80. void InvalidFile(void);
  81. void TooShort(void);
  82.  
  83. /******************************************************************************
  84.  *                            ATrans routines                                 *
  85.  ******************************************************************************/
  86.  
  87. static BOOL checkload(int filetype, BOOL data_open)
  88. {
  89.  /*
  90.   * called when a file is dragged to the app (data_open = FALSE)
  91.   * or double clicked (data_open = TRUE)
  92.   * returns TRUE if the app wants to load that file
  93.   */
  94.  
  95.   switch(filetype)
  96.   {
  97.     case filetype_WIDGET5: /* load widget5 always when enabled */
  98.       return(fullversion);
  99.       break;
  100.  
  101.     case filetype_WIDGET4: /* load widget4 always when enabled */
  102.       return(fullversion);
  103.       break;
  104.  
  105.     case filetype_SPRITE: /* load sprite when dragged only */
  106.       return(!data_open);
  107.       break;
  108.   }
  109.  
  110.   return(FALSE); /* don't load anything else */
  111. }
  112.  
  113. /******************************************************************************/
  114.  
  115. static void loadfile(char *filename, int filetype, BOOL safe)
  116. {
  117.  
  118.   Hourglass_On();
  119.  
  120.   switch(filetype)
  121.   {
  122.     case filetype_WIDGET5:
  123.       load_widget5(filename);
  124.       break;
  125.  
  126.     case filetype_WIDGET4:
  127.       load_widget4(filename);
  128.       break;
  129.  
  130.     case filetype_SPRITE:
  131.       load_sprite(filename);
  132.       break;
  133.  
  134.   }
  135.  
  136.   Hourglass_Off();
  137.  
  138. }
  139.  
  140. /******************************************************************************/
  141.  
  142. extern void LoadSave_savefile(char *filename, int filetype, BOOL safe)
  143. {
  144.  
  145.   if(saveimagebank != -1){
  146.  
  147.      Hourglass_On();
  148.  
  149.      switch(filetype)
  150.      {
  151.        case filetype_WIDGET5:
  152.          SpriteWin_CloseSaveWidget5();
  153.          save_widget5(filename, saveimagebank, savenumbergreys);
  154.          break;
  155.  
  156.        case filetype_WIDGET4:
  157.          SpriteWin_CloseSave();
  158.          save_widget4(filename, saveimagebank);
  159.          break;
  160.  
  161.        case filetype_SPRITE:
  162.          SpriteWin_CloseSave();
  163.          save_sprite(filename, saveimagebank);
  164.          break;
  165.  
  166.      }
  167.  
  168.      Hourglass_Off();
  169.   }
  170.  
  171.   saveimagebank = -1;
  172.  
  173. }
  174.  
  175. /******************************************************************************
  176.  *                            extern routines                                 *
  177.  ******************************************************************************/
  178.  
  179. extern void LoadSave_Init(void)
  180. {
  181.  /*
  182.   * initialisation to be done on startup
  183.   */
  184.  
  185.   ATrans_Init(checkload, loadfile, LoadSave_savefile, NULL);
  186.  
  187. }
  188.  
  189. /******************************************************************************/
  190.  
  191. extern void LoadSave_CheckStartupLoad(int argc, char *argv[])
  192. {
  193.  /*
  194.   * checks to see if the prog was started up by doubleclicking on a file and
  195.   * so loads this file
  196.   */
  197.   int filetype;
  198.  
  199.  /*
  200.   * return if no file to load
  201.   */
  202.   if(argc == 1)
  203.      return;
  204.  
  205.  /*
  206.   * call loadfile with the filename and filetype of the input file
  207.   */
  208.   filetype = File_GetType(argv[1]);
  209.  
  210.   loadfile(argv[1], filetype, TRUE);
  211.  
  212. }
  213.  
  214. /******************************************************************************/
  215.  
  216. extern void LoadSave_SetSaveBank(int imageno, int numbergreys)
  217. {
  218.  /*
  219.   * sets the number of the image bank being saved
  220.   */
  221.   
  222.   saveimagebank = imageno;
  223.   savenumbergreys = numbergreys;
  224.  
  225. }
  226.  
  227. /******************************************************************************
  228.  *                             load routines                                  *
  229.  ******************************************************************************/
  230.  
  231. void load_widget5(char *filename)
  232. {
  233.   tempimage_block *block;
  234.   file_handle channel;
  235.   int value;
  236.   wimp_point res;
  237.   wimp_point pos;
  238.   int numbergreys;
  239.   char *image;
  240.   int linebytes;
  241.   char greys[15];
  242.  
  243.  /*
  244.   * open load file window
  245.   */
  246.   if( (block = open_load(filename, filetype_WIDGET5)) == NULL )
  247.      return;
  248.  
  249. /* from now on block contains 2 malloced areas and the scan routine is on */
  250.  
  251.  /*
  252.   * open file and return if fails
  253.   */
  254.   channel = File_Open(filename, file_READ);
  255.   if(channel == NULL){
  256.      if(file_lasterror != NULL){
  257.         NoLoad(file_lasterror->errmess);
  258.         load_abort1(channel, block);
  259.         return;
  260.      }
  261.   }
  262.  
  263.  /*
  264.   * read in size of image and number of greys
  265.   */
  266.   if( !read_charint(channel, &res.x) ) {
  267.      InvalidFile();
  268.      load_abort1(channel, block);
  269.      return;
  270.   }
  271.  
  272.   if( !read_charint(channel, &res.y) ) {
  273.      InvalidFile();
  274.      load_abort1(channel, block);
  275.      return;
  276.   }
  277.  
  278.   if( !read_charint(channel, &numbergreys) ) {
  279.      InvalidFile();
  280.      load_abort1(channel, block);
  281.      return;
  282.   }
  283.  
  284.  
  285.  /*
  286.   * set size and number of greys in window
  287.   */
  288.   Icon_SetInteger(block->range.window, 4, res.x);
  289.   Icon_SetInteger(block->range.window, 6, res.y);
  290.   Msgs_Lookup("txt.greys", greys, 14);
  291.   Icon_printf(block->range.window, 8, "%i %s", numbergreys, greys);
  292.  
  293.  /*
  294.   * create blank image of correct size
  295.   */
  296.   SpriteWin_InitBlock(block->image, 0);
  297.   if( !SpriteWin_CreateImage(block->image, &res) ) {
  298.      NoMemLoad();
  299.      load_abort1(channel, block);
  300.      return;
  301.   }
  302.   
  303. /* from now on block contains 2 malloc areas, the scan routine is on, and sprite area */
  304.  
  305.   image = (char *)(block->image)->spritearea + (block->image)->image;
  306.   linebytes = (block->image)->linebytes;
  307.  
  308.  /*
  309.   * read in image data, scaled to 256 grey levels
  310.   */
  311.   for(pos.y = 0; pos.y < res.y; pos.y++){
  312.  
  313.      Hourglass_Percentage( (pos.y * 100) / res.y);
  314.   
  315.      for(pos.x = 0; pos.x < res.x; pos.x++){
  316.  
  317.         if( !read_charint(channel, &value) ){
  318.            TooShort();
  319.            File_Close(channel);
  320.            return;
  321.         }
  322.         image[pos.x + (pos.y * linebytes)] = (value * 256) / numbergreys;
  323.      }
  324.   }
  325.  
  326.   File_Close(channel);
  327.  
  328. }
  329.  
  330. /******************************************************************************/
  331.  
  332. void load_widget4(char *filename)
  333. {
  334.   tempimage_block *block;
  335.   file_handle channel;
  336.   wimp_point res;
  337.   wimp_point pos;
  338.   char *image;
  339.   int linebytes;
  340.   char greys[15];
  341.  
  342.  /*
  343.   * open load file window
  344.   */
  345.   if( (block = open_load(filename, filetype_WIDGET4)) == NULL )
  346.      return;
  347.  
  348. /* from now on block contains 2 malloced areas and the scan routine is on */
  349.  
  350.  /*
  351.   * open file and return if fails
  352.   */
  353.   channel = File_Open(filename, file_READ);
  354.   if(channel == NULL){
  355.      if(file_lasterror != NULL){
  356.         NoLoad(file_lasterror->errmess);
  357.         load_abort1(channel, block);
  358.         return;
  359.      }
  360.   }
  361.  
  362.  /*
  363.   * set size and number of greys in window
  364.   */
  365.   res = widget4size;
  366.   
  367.   Icon_SetInteger(block->range.window, 4, res.x);
  368.   Icon_SetInteger(block->range.window, 6, res.y);
  369.   Msgs_Lookup("txt.greys", greys, 14);
  370.   Icon_printf(block->range.window, 8, "256 %s", greys);
  371.  
  372.  /*
  373.   * create blank image of correct size
  374.   */
  375.   SpriteWin_InitBlock(block->image, 0);
  376.   if( !SpriteWin_CreateImage(block->image, &res) ) {
  377.      NoMemLoad();
  378.      load_abort1(channel, block);
  379.      return;
  380.   }
  381.   
  382. /* from now on block contains 2 malloc areas, the scan routine is on, and sprite area */
  383.  
  384.   image = (char *)(block->image)->spritearea + (block->image)->image;
  385.   linebytes = (block->image)->linebytes;
  386.  
  387.  /*
  388.   * read in image data
  389.   */
  390.   for(pos.y = 0; pos.y < res.y; pos.y++){
  391.  
  392.      Hourglass_Percentage( (pos.y * 100) / res.y);
  393.   
  394.      if( File_ReadBytes(channel, &image[pos.y * linebytes], res.x) != 0 ){
  395.         TooShort();
  396.         File_Close(channel);
  397.         return;
  398.      }
  399.      
  400.   }
  401.  
  402.   File_Close(channel);
  403.  
  404. }
  405.  
  406. /******************************************************************************/
  407.  
  408. void load_sprite(char *filename)
  409. {
  410.   tempimage_block *block;
  411.   file_handle channel;
  412.   wimp_point res;
  413.   sprite_header *header;
  414.  
  415.   int spriteoffset;
  416.   int nextoffset;
  417.   int imageoffset;
  418.   int mode;
  419.   int width;
  420.   int height;
  421.   int firstused;
  422.   int lastused;
  423.  
  424.   int fileimagesize;
  425.   int memoryimagesize;
  426.  
  427.   char greys[15];
  428.  
  429.  /*
  430.   * open load file window
  431.   */
  432.   if( (block = open_load(filename, filetype_SPRITE)) == NULL)
  433.      return;
  434.  
  435. /* from now on block contains 2 malloced areas and the scan routine is on */
  436.  
  437.  /*
  438.   * open file and return if fails
  439.   */
  440.   channel = File_Open(filename, file_READ);
  441.   if(channel == NULL){
  442.      if(file_lasterror != NULL){
  443.         NoLoad(file_lasterror->errmess);
  444.         load_abort1(channel, block);
  445.         return;
  446.      }
  447.   }
  448.  
  449.  /*
  450.   * read offset to start of sprite area in file
  451.   */
  452.   File_Seek(channel, 4); /* offset to first sprite */
  453.   spriteoffset = File_ReadInt(channel) - 4;
  454.   if(spriteoffset == file_READERROR){
  455.      InvalidFile();
  456.      load_abort1(channel, block);
  457.      return;
  458.   }
  459.  
  460.  /*
  461.   * read offset to next sprite in file (end of first sprite)
  462.   */
  463.   File_Seek(channel, spriteoffset);
  464.   nextoffset = File_ReadInt(channel);
  465.   if(nextoffset == file_READERROR){
  466.      InvalidFile();
  467.      load_abort1(channel, block);
  468.      return;
  469.   }
  470.  
  471.  /*
  472.   * read width of image in words (32 bits) - 1
  473.   */
  474.   File_Seek(channel, spriteoffset + 16);
  475.   width = File_ReadInt(channel);
  476.   if(width == file_READERROR){
  477.      InvalidFile();
  478.      load_abort1(channel, block);
  479.      return;
  480.   }
  481.  
  482.  /*
  483.   * read height of image in scan lines - 1
  484.   */
  485.   height = File_ReadInt(channel);
  486.   if(height == file_READERROR){
  487.      InvalidFile();
  488.      load_abort1(channel, block);
  489.      return;
  490.   }
  491.  
  492.  /*
  493.   * read first used bit in line of data value
  494.   */
  495.   firstused = File_ReadInt(channel);
  496.   if(firstused == file_READERROR){
  497.      InvalidFile();
  498.      load_abort1(channel, block);
  499.      return;
  500.   }
  501.  
  502.  /*
  503.   * read last used bit (in last word) in line of data value
  504.   */
  505.   lastused = File_ReadInt(channel);
  506.   if(lastused == file_READERROR){
  507.      InvalidFile();
  508.      load_abort1(channel, block);
  509.      return;
  510.   }
  511.  
  512.  /*
  513.   * read offset to start of image data from start of sprite
  514.   */
  515.   imageoffset = File_ReadInt(channel);
  516.   if(imageoffset == file_READERROR){
  517.      InvalidFile();
  518.      load_abort1(channel, block);
  519.      return;
  520.   }
  521.  
  522.  /*
  523.   * read mode sprite is defined in
  524.   */
  525.   File_Seek(channel, spriteoffset + 40); /* mode */
  526.   mode = File_ReadInt(channel);
  527.   if(mode == file_READERROR){
  528.      InvalidFile();
  529.      load_abort1(channel, block);
  530.      return;
  531.   }
  532.  
  533. /* should check mode for 8bit, maybe later */
  534.  
  535.  /*
  536.   * abort if data is not aligned to left of first word
  537.   */
  538.   if(firstused != 0){
  539.      InvalidFile();
  540.      load_abort1(channel, block);
  541.      return;
  542.   }
  543.  
  544.  /*
  545.   * calculate resolution of image
  546.   */
  547.   res.x = (width * 4) - ((firstused + 1) / 8) + ((lastused + 1) / 8);
  548.   res.y = height + 1;
  549.  
  550.  /*
  551.   * set size and number of greys in window
  552.   */
  553.   Icon_SetInteger(block->range.window, 4, res.x);
  554.   Icon_SetInteger(block->range.window, 6, res.y);
  555.   Msgs_Lookup("txt.greys", greys, 14);
  556.   Icon_printf(block->range.window, 8, "256 %s", greys);
  557.  
  558.  /*
  559.   * create blank image of correct size
  560.   */
  561.   SpriteWin_InitBlock(block->image, 0);
  562.   if( !SpriteWin_CreateImage(block->image, &res) ) {
  563.      NoMemLoad();
  564.      load_abort1(channel, block);
  565.      return;
  566.   }
  567.   
  568. /* from now on block contains 2 malloc areas, the scan routine is on, and sprite area */
  569.  
  570.  /*
  571.   * calculate size of image data in file
  572.   */
  573.   fileimagesize = nextoffset - imageoffset;
  574.  
  575.  /*
  576.   * calculate size of image data that can be held in memory
  577.   */
  578.   header = (void *) ((char *)(block->image)->spritearea +
  579.                              ((block->image)->spritearea)->firstoffset);
  580.   memoryimagesize = header->offset_next - header->imageoffset;
  581.  
  582.  
  583.  /*
  584.   * check if there is enough room in sprite area in memory and abort if not
  585.   */
  586.   if(memoryimagesize < fileimagesize){
  587.      InvalidFile();
  588.      load_abort2(channel, block);
  589.      return;
  590.   }
  591.  
  592.  /*
  593.   * read in image data
  594.   */
  595.   File_Seek(channel, spriteoffset + imageoffset);
  596.   if(File_ReadBytes(channel,
  597.                  (char *)(block->image)->spritearea + (block->image)->image,
  598.                  fileimagesize) != 0){
  599.      TooShort();
  600.   }
  601.  
  602.   File_Close(channel);
  603.  
  604. }
  605.  
  606. /******************************************************************************/
  607.  
  608. void load_abort1(file_handle channel, tempimage_block *block)
  609. {
  610.  /*
  611.   * closes file if open, deallocates both blocks and turns off scan routines
  612.   */
  613.   
  614.   if(channel != NULL)
  615.      File_Close(channel);
  616.  
  617.   CheckBanks_RemoveScanFree(&block->range);
  618.  
  619.   Window_Delete(block->range.window);
  620.  
  621.   free(block->image);
  622.  
  623.   free(block);
  624.  
  625. }
  626.  
  627. /******************************************************************************/
  628.  
  629. void load_abort2(file_handle channel, tempimage_block *block)
  630. {
  631.  /*
  632.   * closes file if open, deallocates both blocks, turns off scan routines
  633.   * and frees the flex block spritearea
  634.   */
  635.   
  636.   if(channel != NULL)
  637.      File_Close(channel);
  638.  
  639.   CheckBanks_RemoveScanFree(&block->range);
  640.  
  641.   Window_Delete(block->range.window);
  642.  
  643.   flex_free((flex_ptr) &(block->image)->spritearea);
  644.  
  645.   free(block->image);
  646.  
  647.   free(block);
  648.  
  649. }
  650.  
  651. /******************************************************************************
  652.  *                             save routines                                  *
  653.  ******************************************************************************/
  654.  
  655. void save_widget5(char *filename, int imageno, int numbergreys)
  656. {
  657.   spritewin_block *block;
  658.   file_handle channel;
  659.   char buffer[15];
  660.   wimp_point pos;
  661.   int value;
  662.   char *image;
  663.   int linebytes;
  664.   
  665.  
  666.   block = SpriteWin_GetImageBlock(imageno);
  667.  
  668.  /*
  669.   * don't save if there isn't really an image
  670.   */
  671.   if(block->spritearea == NULL)
  672.      return;
  673.  
  674.  /*
  675.   * open file and return if fails
  676.   */
  677.   channel = File_Open(filename, file_WRITE);
  678.   if(channel == NULL){
  679.      if(file_lasterror != NULL){
  680.         NoSave(file_lasterror->errmess);
  681.         return;
  682.      }
  683.   }
  684.  
  685.  /*
  686.   * set filetype
  687.   */
  688.   File_SetType(filename, filetype_WIDGET5);
  689.  
  690.  /*
  691.   * write image size
  692.   */
  693.   sprintf(buffer, "%i", block->size.x);
  694.   if(!write_text(channel, buffer, 0)) {
  695.      NoSave(file_lasterror->errmess);
  696.      File_Close(channel);
  697.      return;
  698.   }
  699.   if(!write_newline(channel)) {
  700.      NoSave(file_lasterror->errmess);
  701.      File_Close(channel);
  702.      return;
  703.   }
  704.  
  705.   sprintf(buffer, "%i", block->size.y);
  706.   if(!write_text(channel, buffer, 0)) {
  707.      NoSave(file_lasterror->errmess);
  708.      File_Close(channel);
  709.      return;
  710.   }
  711.   if(!write_newline(channel)) {
  712.      NoSave(file_lasterror->errmess);
  713.      File_Close(channel);
  714.      return;
  715.   }
  716.  
  717.  /*
  718.   * write number of greys
  719.   */
  720.   sprintf(buffer, "%i", numbergreys);
  721.   if(!write_text(channel, buffer, 0)) {
  722.      NoSave(file_lasterror->errmess);
  723.      File_Close(channel);
  724.      return;
  725.   }
  726.   if(!write_newline(channel)) {
  727.      NoSave(file_lasterror->errmess);
  728.      File_Close(channel);
  729.      return;
  730.   }
  731.  
  732.  /*
  733.   * write image data
  734.   */
  735.   image = (char *)block->spritearea + block->image;
  736.   linebytes = block->linebytes;
  737.  
  738.   for(pos.y = 0; pos.y < block->size.y; pos.y++){
  739.  
  740.      Hourglass_Percentage( (pos.y * 100) / block->size.y);
  741.  
  742.      for(pos.x = 0; pos.x < block->size.x; pos.x++){
  743.  
  744.         value = (image[pos.x + (pos.y * linebytes)] * numbergreys) / 256;
  745.         sprintf(buffer, "%i", value);
  746.         if(!write_text(channel, buffer, 4)) {
  747.            NoSave(file_lasterror->errmess);
  748.            File_Close(channel);
  749.            return;
  750.         }
  751.      }
  752.  
  753.      if(!write_newline(channel)) {
  754.         NoSave(file_lasterror->errmess);
  755.         File_Close(channel);
  756.         return;
  757.      }
  758.  
  759.   }
  760.   
  761.   File_Close(channel);
  762.   
  763. }
  764.  
  765. /******************************************************************************/
  766.  
  767. void save_widget4(char *filename, int imageno)
  768. {
  769.   spritewin_block *block;
  770.   file_handle channel;
  771.   wimp_point pos;
  772.   char *image;
  773.   int linebytes;
  774.   
  775.  
  776.   block = SpriteWin_GetImageBlock(imageno);
  777.  
  778.  /*
  779.   * don't save if there isn't really an image
  780.   */
  781.   if(block->spritearea == NULL)
  782.      return;
  783.  
  784.  /*
  785.   * open file and return if fails
  786.   */
  787.   channel = File_Open(filename, file_WRITE);
  788.   if(channel == NULL){
  789.      if(file_lasterror != NULL){
  790.         NoSave(file_lasterror->errmess);
  791.         return;
  792.      }
  793.   }
  794.  
  795.  /*
  796.   * set filetype
  797.   */
  798.   File_SetType(filename, filetype_WIDGET4);
  799.  
  800.  /*
  801.   * write image data
  802.   */
  803.   image = (char *)block->spritearea + block->image;
  804.   linebytes = block->linebytes;
  805.  
  806.   for(pos.y = 0; pos.y < block->size.y; pos.y++){
  807.  
  808.      Hourglass_Percentage( (pos.y * 100) / block->size.y);
  809.  
  810.      if( File_WriteBytes(channel, &image[pos.y * linebytes], block->size.x) != 0 ){
  811.         NoSave(file_lasterror->errmess);
  812.         File_Close(channel);
  813.         return;
  814.      }
  815.  
  816.   }
  817.   
  818.   File_Close(channel);
  819.   
  820. }
  821.  
  822. /******************************************************************************/
  823.  
  824. void save_sprite(char *filename, int imageno)
  825. {
  826.   spritewin_block *block;
  827.  
  828.   block = SpriteWin_GetImageBlock(imageno);
  829.  
  830.  /*
  831.   * don't save if there isn't really an image
  832.   */
  833.   if(block->spritearea == NULL)
  834.      return;
  835.  
  836.   Error_Check(Sprite_Save(block->spritearea, filename));
  837.  
  838. }
  839.  
  840. /******************************************************************************
  841.  *                             open routines                                  *
  842.  ******************************************************************************/
  843.  
  844. tempimage_block *open_load(char *filename, int filetype)
  845. {
  846.  /*
  847.   * open place loaded image window on screen
  848.   */
  849.   tempimage_block *block;
  850.  
  851.  /*
  852.   * allocate memory for range info block and return NULL if error if fails
  853.   */
  854.   block = malloc(sizeof(tempimage_block));
  855.   if(block == NULL){
  856.      NoMemLoad();
  857.      return(block);
  858.   }
  859.  
  860.  /*
  861.   * allocate memory for image bank info block, deallocate block and return NULL if fails
  862.   */
  863.   block->image = malloc(sizeof(spritewin_block));
  864.   if(block->image == NULL){
  865.      NoMemLoad();
  866.      free(block);
  867.      block = NULL;
  868.      return(block);
  869.   }
  870.  
  871.  /*
  872.   * create window and fill range info block
  873.   */
  874.   block->range.window = Window_Create("Load", template_TITLEMIN);
  875.   block->range.min = image_MIN;
  876.   block->range.max = image_MAX;
  877.  
  878.  /*
  879.   * filename
  880.   */
  881.   Icon_SetTextRJ(block->range.window, 3, filename);
  882.  
  883.  /*
  884.   * set filetype of icon
  885.   */
  886.   Icon_SetFileType(block->range.window, 2, filetype);
  887.  
  888.   CheckBanks_InstallScanFree(&block->range);
  889.  
  890.  /*
  891.   * install event handlers
  892.   */
  893.   Event_Claim(event_CLICK, block->range.window, event_ANY, Click_load, block);
  894.  
  895.   Event_Claim(event_CLOSE, block->range.window, event_ANY, Close_load, block);
  896.  
  897.   Window_Show(block->range.window, open_WHEREVER);
  898.  
  899.   return(block);
  900. }
  901.  
  902. /******************************************************************************
  903.  *                            close routines                                  *
  904.  ******************************************************************************/
  905.  
  906. void close_load(tempimage_block *block, BOOL ok)
  907. {
  908.   int imageno;
  909.  
  910.   if(ok == TRUE){
  911.  
  912.      imageno = image_getselect(&block->range);
  913.  
  914.     /*
  915.      * don't do anything if no bank is selected
  916.      */
  917.      if(imageno == -1)
  918.         return;
  919.  
  920.     /*
  921.      * add image bank info block to list but do nothing if bank used
  922.      */
  923.      if( !SpriteWin_AddImageBlock(block->image, imageno) )
  924.         return;
  925.  
  926.     /*
  927.      * create window
  928.      */
  929.      SpriteWin_CreateWindow(block->image);
  930.  
  931.  
  932.   }
  933.   else{
  934.      flex_free((flex_ptr) &(block->image)->spritearea);
  935.      free(block->image);
  936.   }
  937.  
  938.   CheckBanks_RemoveScanFree(&block->range);
  939.  
  940.   Window_Delete(block->range.window);
  941.  
  942.   free(block);
  943.  
  944. }
  945.  
  946. /******************************************************************************/
  947.  
  948. static BOOL Close_load(event_pollblock *event, void *reference)
  949. {
  950.   close_load((tempimage_block *)reference, FALSE);
  951.  
  952.   return(FALSE);
  953. }
  954.  
  955. /******************************************************************************
  956.  *                              Click handlers                                *
  957.  ******************************************************************************/
  958.  
  959. static BOOL Click_load(event_pollblock *event, void *reference)
  960. {
  961.   tempimage_block *block = reference;
  962.  
  963.   switch(event->data.mouse.icon)
  964.   {
  965.     
  966.     case 17: /* Cancel */
  967.        close_load(block, FALSE);
  968.        break;
  969.  
  970.     case 18: /* Place Loaded Image */
  971.        close_load(block, TRUE);
  972.        break;
  973.       
  974.   }
  975.   return(TRUE);
  976. }
  977.  
  978. /******************************************************************************
  979.  *                               misc routines                                *
  980.  ******************************************************************************/
  981.  
  982. BOOL write_newline(file_handle channel)
  983. {
  984.   if(File_WriteChar(channel, 10) != NULL)
  985.      return(FALSE);
  986.  
  987.   return(TRUE);
  988. }
  989.  
  990. /******************************************************************************/
  991.  
  992. BOOL write_space(file_handle channel)
  993. {
  994.   if(File_WriteChar(channel, ' ') != NULL)
  995.      return(FALSE);
  996.  
  997.   return(TRUE);
  998. }
  999.  
  1000. /******************************************************************************/
  1001.  
  1002. BOOL write_text(file_handle channel, char *text, int padto)
  1003. {
  1004.   int length;
  1005.   int loop;
  1006.  
  1007.  /*
  1008.   * pad out text so that it is RJ with field size 'padto'
  1009.   */
  1010.   if( (length = strlen(text)) < padto){
  1011.  
  1012.      for(loop = 0; loop < (padto - length); loop++){
  1013.  
  1014.          if(!write_space(channel))
  1015.             return(FALSE);
  1016.      }
  1017.   }
  1018.  
  1019.  /*
  1020.   * write text
  1021.   */
  1022.   if( File_WriteBytes(channel, text, length) != 0)
  1023.      return(FALSE);
  1024.  
  1025.   return(TRUE);
  1026. }
  1027.  
  1028. /******************************************************************************/
  1029.  
  1030. BOOL read_charint(file_handle channel, int *integer)
  1031. {
  1032.  /*
  1033.   * reads in a text number and returns it in 'interger'
  1034.   * FALSE is returned if the read fails on the first try (EOF)
  1035.   */
  1036.   #define sizeof_BUFFER 15
  1037.   char buffer[15];
  1038.   int index;
  1039.   int character;
  1040.  
  1041.  /*
  1042.   * read in text up to divider character or EOF
  1043.   */
  1044.   index = 0;
  1045.  
  1046.  /*
  1047.   * skip any chars before number
  1048.   */
  1049.   while( ((character = File_ReadChar(channel)) != file_READERROR) &&
  1050.          (character <= ' ') );
  1051.  
  1052.  /*
  1053.   * 'character' is now either the first number character or file_READERROR
  1054.   */
  1055.   if(character != file_READERROR){
  1056.  
  1057.      buffer[index++] = (char) character;
  1058.  
  1059.      while( ((character = File_ReadChar(channel)) != file_READERROR) &&
  1060.             (character > ' ') && (index < (sizeof_BUFFER - 1)) ){
  1061.  
  1062.         buffer[index++] = (char) character;
  1063.      }
  1064.   }
  1065.   buffer[index] = 0; /* terminate string */
  1066.  
  1067.  /*
  1068.   * convert text number to integer
  1069.   */
  1070.   *integer = atoi(buffer);
  1071.  
  1072.  /*
  1073.   * return TRUE if not at end of file
  1074.   */
  1075.   return( !((index == 0) && (character == file_READERROR)) );
  1076. }
  1077.  
  1078. /******************************************************************************/
  1079.  
  1080. void NoLoad(char *err)
  1081. {
  1082.   char err_msg[128];
  1083.  
  1084.   Msgs_Lookup("err.noload", err_msg, 127);
  1085.   Error_Report(1,err_msg, err);
  1086.  
  1087. }
  1088.  
  1089. /******************************************************************************/
  1090.  
  1091. void NoMemLoad(void)
  1092. {
  1093.   char err_msg[128];
  1094.  
  1095.   Msgs_Lookup("err.nomemload", err_msg, 127);
  1096.   Error_Report(1,err_msg);
  1097.  
  1098. }
  1099.  
  1100. /******************************************************************************/
  1101.  
  1102. void NoSave(char *err)
  1103. {
  1104.   char err_msg[128];
  1105.  
  1106.   Msgs_Lookup("err.nosave", err_msg, 127);
  1107.   Error_Report(1,err_msg, err);
  1108.  
  1109. }
  1110.  
  1111. /******************************************************************************/
  1112.  
  1113. void InvalidFile(void)
  1114. {
  1115.   char err_msg[128];
  1116.  
  1117.   Msgs_Lookup("err.invfile", err_msg, 127);
  1118.   Error_Report(1,err_msg);
  1119.  
  1120. }
  1121.  
  1122. /******************************************************************************/
  1123.  
  1124. void TooShort(void)
  1125. {
  1126.   char err_msg[128];
  1127.  
  1128.   Msgs_Lookup("err.short", err_msg, 127);
  1129.   Error_Report(1,err_msg);
  1130.  
  1131. }
  1132.  
  1133.