]> granicus.if.org Git - nethack/commitdiff
zlib support; also internal compression changes
authornethack.allison <nethack.allison>
Sat, 22 Jan 2005 15:28:15 +0000 (15:28 +0000)
committernethack.allison <nethack.allison>
Sat, 22 Jan 2005 15:28:15 +0000 (15:28 +0000)
o Add support for zlib compression via ZLIB_COMP in config.h (ZLIB_COMP
  and COMPRESS are mutually exclusive).
o rlecomp and zerocomp are run time options available if RLECOMP and
  ZEROCOMP are defined, but not turned on by default if either COMPRESS
  or ZLIB_COMP are defined.
o Add information to the save file about internal compression options
  used when writing the save file, particularly rlecomp and zerocomp
  support.
o Automatically adjust rlecomp and zerocomp (if support compiled in)
  when reading in an existing savefile that was saved with those options
  turned on.  Still allows writing out of savefile in preferred format.
o In order to support zlib and not conflict with compress and uncompress
  routines there, the NetHack internal functions were changed to
  nh_uncompress and nh_compress as done in the zlib contribution received
  in 1999 from <Someone>.

I tagged the sources NETHACK_3_5_0_PREZLIB prior to applying these
changes.

20 files changed:
doc/Guidebook.mn
doc/Guidebook.tex
include/config.h
include/decl.h
include/extern.h
include/flag.h
include/global.h
src/bones.c
src/decl.c
src/files.c
src/options.c
src/restore.c
src/save.c
sys/be/bemain.c
sys/mac/macmain.c
sys/share/pcmain.c
sys/unix/Makefile.src
sys/unix/unixmain.c
sys/winnt/Makefile.msc
util/makedefs.c

index a28a71e3dc7ba55eeb5115568db99477ff24cb7a..403ddf9d1dba6250756cc485ec9f402510ce1ff4 100644 (file)
@@ -2086,6 +2086,10 @@ of specifying your role.  Normally only the first letter of the
 value is examined; `r' is an exception with ``Rogue'', ``Ranger'',
 and ``random'' values. If you prefix a `!' or ``no'' to the value, you can 
 exclude that role from being picked randomly.
+.lp rlecomp
+When writing out a save file, perform run length compression of level 
+structures. Not all ports support run length compression. It has no
+effect on reading an existing save file.
 .lp runmode
 Controls the amount of screen updating for the map window when engaged
 in multi-turn movement (running via shift+direction or control+direction
@@ -2173,6 +2177,10 @@ Provide more commentary during the game (default on).
 Select which windowing system to use, such as ``tty'' or ``X11''
 (default depends on version).
 Cannot be set with the `O' command.
+.lp zerocomp
+When writing out a save file, perform zero-comp compression of the 
+contents. Not all ports support zero-comp compression. It has no effect 
+on reading an existing save file.
 .hn 2
 Window Port Customization options
 .pg
index 4fb7e528f8aab14a21988fc36658a0ee47e108a8..36eb28a593fb70345c5b9184bac66a673672d6b4 100644 (file)
@@ -27,7 +27,7 @@
 \begin{document}
 %
 % input file: guidebook.mn
-% $Revision: 1.89 $ $Date: 2005/01/09 21:40:02 $
+% $Revision: 1.90 $ $Date: 2005/01/16 03:57:39 $
 %
 %.ds h0 "
 %.ds h1 %.ds h2 \%
@@ -2554,6 +2554,11 @@ value is examined; `r' is an exception with ``{\tt Rogue}'', {\tt Ranger}'',
 and ``{\tt random}'' values. If you prefix `{\tt !}' or ``{\tt no}'' to the 
 value, you can exclude that role from being picked randomly.
 %.lp
+\item[\ib{rlecomp}]
+When writing out a save file, perform run length compression of level 
+structures. Not all ports support run length compression. It has no
+effect on reading an existing save file.
+%.lp
 \item[\ib{runmode}]
 Controls the amount of screen updating for the map window when engaged
 in multi-turn movement (running via {\tt shift}+direction
@@ -2658,6 +2663,11 @@ Provide more commentary during the game (default on).
 Select which windowing system to use, such as ``{\tt tty}'' or ``{\tt X11}''
 (default depends on version).
 Cannot be set with the `{\tt O}' command.
+%.lp
+\item[\ib{zerocomp}]
+When writing out a save file, perform zero-comp compression of the 
+contents. Not all ports support zero-comp compression. It has no effect 
+on reading an existing save file.
 \elist
 
 %.hn 2
index 2b61a1aa7d7f4119821d89ed1625ca84850dc598..1351c0ddc585d13ca471f525af5741f93af5714c 100644 (file)
 
 /*
  *     If COMPRESS is defined, it should contain the full path name of your
- *     'compress' program.  Defining INTERNAL_COMP causes NetHack to do
- *     simpler byte-stream compression internally.  Both COMPRESS and
- *     INTERNAL_COMP create smaller bones/level/save files, but require
- *     additional code and time.  Currently, only UNIX fully implements
- *     COMPRESS; other ports should be able to uncompress save files a
- *     la unixmain.c if so inclined.
+ *     'compress' program.
+ *
  *     If you define COMPRESS, you must also define COMPRESS_EXTENSION
  *     as the extension your compressor appends to filenames after
- *     compression.
+ *     compression. Currently, only UNIX fully implements
+ *     COMPRESS; other ports should be able to uncompress save files a
+ *     la unixmain.c if so inclined.
+ *
+ *     Defining ZLIB_COMP builds in support for zlib compression. If you
+ *     define ZLIB_COMP, you must link with a zlib library.
+ *
+ *     COMPRESS and ZLIB_COMP are mutually exclusive.
+ *
  */
-
-#ifdef UNIX
+#if defined(UNIX) && !defined(ZLIB_COMP) && !defined(COMPRESS)
 /* path and file name extension for compression program */
 #define COMPRESS "/usr/bin/compress"   /* Lempel-Ziv compression */
 #define COMPRESS_EXTENSION ".Z"                /* compress's extension */
 #endif
 
 #ifndef COMPRESS
-# define INTERNAL_COMP /* control use of NetHack's compression routines */
+# define ZLIB_COMP                     /* ZLIB for compression */
 #endif
 
+/*
+ *     Internal Compression Options
+ *
+ *     Internal compression options RLECOMP and ZEROCOMP alter the data
+ *     that gets written to the save file by NetHack, in contrast
+ *     to COMPRESS or ZLIB_COMP which compress the entire file after
+ *     the NetHack data is written out.
+ *
+ *     Defining RLECOMP builds in support for internal run-length
+ *     compression of level structures. If RLECOMP support is included
+ *     it can be toggled on/off at runtime via the config file option
+ *     rlecomp.
+ *
+ *     Defining ZEROCOMP builds in support for internal zero-comp
+ *     compression of data. If ZEROCOMP support is included it can still
+ *     be toggled on/off at runtime via the config file option zerocomp.
+ *
+ *     RLECOMP and ZEROCOMP support can be included even if
+ *     COMPRESS or ZLIB_COMP support is included. One reason for doing
+ *     so would be to provide savefile read compatibility with a savefile
+ *     where those options were in effect. With RLECOMP and/or ZEROCOMP
+ *     defined, NetHack can read an rlecomp or zerocomp savefile in, yet
+ *     re-save without them.
+ *
+ *     Using any compression option will create smaller bones/level/save
+ *     files at the cost of additional code and time.
+ */
+
+/* # define INTERNAL_COMP      */      /* Forces both ZEROCOMP and RLECOMP */
+/* # define ZEROCOMP           */      /* Support ZEROCOMP compression */
+/* # define RLECOMP            */      /* Support RLECOMP compression  */
+
 /*
  *     Data librarian.  Defining DLB places most of the support files into
  *     a tar-like file, thus making a neater installation.  See *conf.h
index ecfa12f535ace48c3e7ba2032fe7f9631845482c..35e99bb77aba91fe53ada332a92bd2fdaa5f68f8 100644 (file)
@@ -381,6 +381,8 @@ E char *fqn_prefix[PREFIX_COUNT];
 E char *fqn_prefix_names[PREFIX_COUNT];
 #endif
 
+E NEARDATA struct savefile_info sfcap, sfrestinfo, sfsaveinfo;
+
 #ifdef AUTOPICKUP_EXCEPTIONS
 struct autopickup_exception {
        char *pattern;
index dac2fa9bf277d4ffa23a58a4fcee24fdad5c8f59..34b3e2643c7b4b80bd591204912ce89aa23ee3c0 100644 (file)
@@ -673,8 +673,8 @@ E int NDECL(create_savefile);
 E int NDECL(open_savefile);
 E int NDECL(delete_savefile);
 E int NDECL(restore_saved_game);
-E void FDECL(compress, (const char *));
-E void FDECL(uncompress, (const char *));
+E void FDECL(nh_compress, (const char *));
+E void FDECL(nh_uncompress, (const char *));
 E boolean FDECL(lock_file, (const char *,int,int));
 E void FDECL(unlock_file, (const char *));
 #ifdef USER_SOUNDS
@@ -1751,14 +1751,14 @@ E void FDECL(getlev, (int,int,XCHAR_P,BOOLEAN_P));
 E void FDECL(get_plname_from_file, (int, char *));
 E void NDECL(minit);
 E boolean FDECL(lookup_id_mapping, (unsigned, unsigned *));
-#ifdef ZEROCOMP
-E int FDECL(mread, (int,genericptr_t,unsigned int));
-#else
 E void FDECL(mread, (int,genericptr_t,unsigned int));
-#endif
 #ifndef GOLDOBJ
 E void FDECL(put_gold_back, (struct obj **,long *));
 #endif
+E int FDECL(validate, (int,const char *));
+E void NDECL(reset_restpref);
+E void FDECL(set_restpref, (const char *));
+E void FDECL(set_savepref, (const char *));
 
 /* ### rip.c ### */
 
@@ -1835,10 +1835,15 @@ E void FDECL(bufoff, (int));
 E void FDECL(bflush, (int));
 E void FDECL(bwrite, (int,genericptr_t,unsigned int));
 E void FDECL(bclose, (int));
+E void FDECL(def_bclose, (int));
+#if defined(ZEROCOMP)
+E void FDECL(zerocomp_bclose, (int));
+#endif
 E void FDECL(savefruitchn, (int,int));
 E void FDECL(store_plname_in_file, (int));
 E void NDECL(free_dungeons);
 E void NDECL(freedynamicdata);
+E void FDECL(store_savefileinfo, (int));
 
 /* ### shk.c ### */
 
index 465d0295a595e85b9832457ccb883bcbefa4a7e9..f690cdbca8492799264db5a6c118370a0f23b0e0 100644 (file)
@@ -164,6 +164,8 @@ struct instance_flags {
        boolean  menu_tab_sep;  /* Use tabs to separate option menu fields */
        boolean  menu_requested; /* Flag for overloaded use of 'm' prefix
                                  * on some non-move commands */
+       boolean  zerocomp;      /* write zero-compressed save files */
+       boolean  rlecomp;       /* run-length comp of levels when writing savefile */
        uchar num_pad_mode;
        int     menu_headings;  /* ATR for menu headings */
        int      purge_monsters;        /* # of dead monsters still on fmon list */
index 8c26e705946f6f9d29f9c9eb96ca8356f164a219..f69b867f2383857ffe988f101b0b8401b0e11433 100644 (file)
@@ -305,6 +305,20 @@ struct version_info {
        unsigned long   struct_sizes2;  /* size of more key structs */
 };
 
+struct savefile_info {
+       unsigned long   sfi1;   /* compression etc. */
+       unsigned long   sfi2;   /* miscellaneous */
+       unsigned long   sfi3;   /* thirdparty */
+};
+#ifdef NHSTDC
+#define SFI1_EXTERNALCOMP      (1UL)
+#define SFI1_RLECOMP           (1UL << 1)
+#define SFI1_ZEROCOMP          (1UL << 2)
+#else
+#define SFI1_EXTERNALCOMP      (1L)
+#define SFI1_RLECOMP           (1L << 1)
+#define SFI1_ZEROCOMP          (1L << 2)
+#endif
 
 /*
  * Configurable internal parameters.
index 69e51997fdb283e4527c947a8a634fab840cf79a..44e2e536232bbd6983489366254ff648c54ac219 100644 (file)
@@ -427,12 +427,14 @@ getbones()
        fd = open_bonesfile(&u.uz, &bonesid);
        if (fd < 0) return(0);
 
-       if ((ok = uptodate(fd, bones)) == 0) {
+       if (validate(fd, bones) != 0) {
 #ifdef WIZARD
            if (!wizard)
 #endif
                pline("Discarding unuseable bones; no need to panic...");
+           ok = FALSE;
        } else {
+               ok = TRUE;
 #ifdef WIZARD
                if(wizard)  {
                        if(yn("Get bones?") == 'n') {
index 72ae782e6692f8d8b393153439106535d2ee8b61..cdde3333c3efddaa9fce54a76901587d197228d5 100644 (file)
@@ -275,6 +275,52 @@ char *fqn_prefix_names[PREFIX_COUNT] = { "hackdir", "leveldir", "savedir",
                                        "lockdir", "configdir", "troubledir" };
 #endif
 
+NEARDATA struct savefile_info sfcap = {
+#ifdef NHSTDC
+               0x00000000UL
+#else
+               0x00000000L
+#endif
+#if defined(COMPRESS) || defined(ZLIB_COMP)
+               | SFI1_EXTERNALCOMP
+#endif
+#if defined(ZEROCOMP)
+               | SFI1_ZEROCOMP
+#endif
+#if defined(RLECOMP)
+               | SFI1_RLECOMP
+#endif
+       ,
+#ifdef NHSTDC
+       0x00000000UL, 0x00000000UL
+#else
+       0x00000000L, 0x00000000L
+#endif
+};
+
+NEARDATA struct savefile_info sfrestinfo, sfsaveinfo = {
+#ifdef NHSTDC
+               0x00000000UL
+#else
+               0x00000000L
+#endif
+#if defined(COMPRESS) || defined(ZLIB_COMP)
+               | SFI1_EXTERNALCOMP
+#endif
+#if defined(ZEROCOMP)
+               | SFI1_ZEROCOMP
+#endif
+#if defined(RLECOMP)
+               | SFI1_RLECOMP
+#endif
+       ,
+#ifdef NHSTDC
+       0x00000000UL, 0x00000000UL
+#else
+       0x00000000L, 0x00000000L
+#endif
+};
+
 /* dummy routine used to force linkage */
 void
 decl_init()
index fcc1a2e54656879e0684f63910f4337931759b15..7254b6489db608e04fd911b01241f930a0627107 100644 (file)
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)files.c    3.5     2004/11/22      */
+/*     SCCS Id: @(#)files.c    3.5     2005/01/04      */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -32,6 +32,13 @@ const
 extern int errno;
 #endif
 
+#ifdef ZLIB_COMP       /* RLC 09 Mar 1999: Support internal ZLIB */
+#include "zlib.h"
+# ifndef COMPRESS_EXTENSION
+#define COMPRESS_EXTENSION ".gz"
+# endif
+#endif
+  
 #if defined(UNIX) && defined(QT_GRAPHICS)
 #include <sys/types.h>
 #include <dirent.h>
@@ -158,6 +165,8 @@ STATIC_DCL char *FDECL(set_bonesfile_name, (char *,d_level*));
 STATIC_DCL char *NDECL(set_bonestemp_name);
 #ifdef COMPRESS
 STATIC_DCL void FDECL(redirect, (const char *,const char *,FILE *,BOOLEAN_P));
+#endif
+#if defined(COMPRESS) || defined(ZLIB_COMP)
 STATIC_DCL void FDECL(docompress_file, (const char *,BOOLEAN_P));
 #endif
 STATIC_DCL char *FDECL(make_lockname, (const char *,char *));
@@ -770,7 +779,7 @@ char **bonesid;
 
        *bonesid = set_bonesfile_name(bones, lev);
        fq_bones = fqname(bones, BONESPREFIX, 0);
-       uncompress(fq_bones);   /* no effect if nonexistent */
+       nh_uncompress(fq_bones);        /* no effect if nonexistent */
 #ifdef MAC
        fd = macopen(fq_bones, O_RDONLY | O_BINARY, BONE_TYPE);
 #else
@@ -794,7 +803,7 @@ d_level *lev;
 void
 compress_bonesfile()
 {
-       compress(fqname(bones, BONESPREFIX, 0));
+       nh_compress(fqname(bones, BONESPREFIX, 0));
 }
 
 /* ----------  END BONES FILE HANDLING ----------- */
@@ -945,6 +954,7 @@ restore_saved_game()
        const char *fq_save;
        int fd;
 
+       reset_restpref();
        set_savefile_name();
 #ifdef MFLOPPY
        if (!saveDiskPrompt(1))
@@ -952,10 +962,10 @@ restore_saved_game()
 #endif /* MFLOPPY */
        fq_save = fqname(SAVEF, SAVEPREFIX, 0);
 
-       uncompress(fq_save);
+       nh_uncompress(fq_save);
        if ((fd = open_savefile()) < 0) return fd;
 
-       if (!uptodate(fd, fq_save)) {
+       if (validate(fd, fq_save) != 0) {
            (void) close(fd),  fd = -1;
            (void) delete_savefile();
        }
@@ -975,16 +985,16 @@ const char* filename;
 #  ifdef COMPRESS_EXTENSION
     SAVEF[strlen(SAVEF)-strlen(COMPRESS_EXTENSION)] = '\0';
 #  endif
-    uncompress(SAVEF);
+    nh_uncompress(SAVEF);
     if ((fd = open_savefile()) >= 0) {
-       if (uptodate(fd, filename)) {
+       if (validate(fd, filename)==0) {
            char tplname[PL_NSIZ];
            get_plname_from_file(fd, tplname);
            result = strdup(tplname);
        }
        (void) close(fd);
     }
-    compress(SAVEF);
+    nh_compress(SAVEF);
 
     return result;
 # if 0
@@ -1033,6 +1043,9 @@ get_saved_games()
        (void)fname_encode("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-.",
                                '%', fnamebuf, encodedfnamebuf, BUFSZ);
        Sprintf(SAVEF, "%s*.NetHack-saved-game", encodedfnamebuf);
+#if defined(ZLIB_COMP)
+       Strcat(SAVEF, COMPRESS_EXTENSION);
+#endif
        fq_save = fqname(SAVEF, SAVEPREFIX, 0);
 
        n = 0;
@@ -1278,10 +1291,10 @@ boolean uncomp;
 
 /* compress file */
 void
-compress(filename)
+nh_compress(filename)
 const char *filename;
 {
-#ifndef COMPRESS
+#if !defined(COMPRESS) && !defined(ZLIB_COMP)
 #if (defined(macintosh) && (defined(__SC__) || defined(__MRC__))) || defined(__MWERKS__)
 # pragma unused(filename)
 #endif
@@ -1293,10 +1306,10 @@ const char *filename;
 
 /* uncompress file if it exists */
 void
-uncompress(filename)
+nh_uncompress(filename)
 const char *filename;
 {
-#ifndef COMPRESS
+#if !defined(COMPRESS) && !defined(ZLIB_COMP)
 #if (defined(macintosh) && (defined(__SC__) || defined(__MRC__))) || defined(__MWERKS__)
 # pragma unused(filename)
 #endif
@@ -1305,6 +1318,174 @@ const char *filename;
 #endif
 }
 
+#ifdef ZLIB_COMP /* RLC 09 Mar 1999: Support internal ZLIB */
+static int
+make_compressed_name(filename,cfn)
+const char *filename;
+char *cfn;
+{
+#ifndef SHORT_FILENAMES
+       /* Assume free-form filename */
+
+       strcpy(cfn, filename);
+       strcat(cfn, COMPRESS_EXTENSION);
+       return TRUE;
+#else
+       /* Accomodates 8.3 restriction, but otherwise assumes free-form filenames.
+          This may need to be revised for some systems.  If a name cannot be
+          generated, this function may return FALSE and the file will then remain
+          uncompressed. */
+       unsigned len;
+
+       /* Assume DOS style filename */
+
+       strcpy(cfn, filename);
+       len = strlen(cfn);
+       if (len>4 && stricmp(cfn+len-4,".sav")==0) {
+               /* Save file; change .SAV extension to .SAZ */
+               /* EMX/GCC (for OS/2) seems to miscompile cfn[len-1] */
+
+               cfn[strlen(cfn)-1]='z';
+               return TRUE;
+       } else if (strnicmp(cfn,"bones",5)==0) {
+               /* Bones file; change BONES prefix to BONEZ */
+
+               cfn[4]='z';
+               return TRUE;
+       } else {
+               /* Don't know how to convert this filename */
+
+               return FALSE;
+       }
+#endif /* !MSDOS */
+}
+
+STATIC_OVL void
+docompress_file(filename, uncomp)
+const char *filename;
+boolean uncomp;
+{
+       gzFile *compressedfile;
+       FILE *uncompressedfile;
+       char cfn[256];
+       char buf[1024];
+       unsigned len, len2;
+
+       if (!make_compressed_name(filename, cfn)) {
+               /* Can't generate a name for the compressed file
+                  due to 8.3 restriction */
+               return;
+       }
+
+       if (!uncomp) {
+               /* Open the input and output files */
+               /* Note that gzopen takes "wb" as its mode, even on systems where
+                  fopen takes "r" and "w" */
+
+               uncompressedfile = fopen(filename, RDBMODE);
+               if (uncompressedfile == NULL) {
+                       perror(filename);
+                       return;
+               }
+               compressedfile = gzopen(cfn, "wb");
+               if (compressedfile == NULL) {
+                       if (errno == 0) {
+                               pline("zlib failed to allocate memory");
+                       } else {
+                               perror(filename);
+                       }
+                       fclose(uncompressedfile);
+                       return;
+               }
+
+               /* Copy from the uncompressed to the compressed file */
+
+               while (1) {
+                       len = fread(buf, 1, sizeof(buf), uncompressedfile);
+                       if (ferror(uncompressedfile)) {
+                               pline("Failure reading uncompressed file");
+                               pline("Can't compress %s.", filename);
+                               fclose(uncompressedfile);
+                               gzclose(compressedfile);
+                               (void)unlink(cfn);
+                               return;
+                       }
+                       if (len == 0) break;    /* End of file */
+
+                       len2 = gzwrite(compressedfile, buf, len);
+                       if (len2 == 0) {
+                               pline("Failure writing compressed file");
+                               pline("Can't compress %s.", filename);
+                               fclose(uncompressedfile);
+                               gzclose(compressedfile);
+                               (void)unlink(cfn);
+                               return;
+                       }
+               }
+
+               fclose(uncompressedfile);
+               gzclose(compressedfile);
+
+               /* Delete the file left behind */
+
+               (void)unlink(filename);
+
+       } else {        /* uncomp */
+
+               /* Open the input and output files */
+               /* Note that gzopen takes "rb" as its mode, even on systems where
+                  fopen takes "r" and "w" */
+
+               compressedfile = gzopen(cfn, "rb");
+               if (compressedfile == NULL) {
+                       if (errno == 0) {
+                               pline("zlib failed to allocate memory");
+                       } else if (errno != ENOENT) {
+                               perror(filename);
+                       }
+                       return;
+               }
+               uncompressedfile = fopen(filename, WRBMODE);
+               if (uncompressedfile == NULL) {
+                       perror(filename);
+                       gzclose(compressedfile);
+                       return;
+               }
+
+               /* Copy from the compressed to the uncompressed file */
+
+               while (1) {
+                       len = gzread(compressedfile, buf, sizeof(buf));
+                       if (len == (unsigned)-1) {
+                               pline("Failure reading compressed file");
+                               pline("Can't uncompress %s.", filename);
+                               fclose(uncompressedfile);
+                               gzclose(compressedfile);
+                               (void)unlink(filename);
+                               return;
+                       }
+                       if (len == 0) break;    /* End of file */
+
+                       fwrite(buf, 1, len, uncompressedfile);
+                       if (ferror(uncompressedfile)) {
+                               pline("Failure writing uncompressed file");
+                               pline("Can't uncompress %s.", filename);
+                               fclose(uncompressedfile);
+                               gzclose(compressedfile);
+                               (void)unlink(filename);
+                               return;
+                       }
+               }
+
+               fclose(uncompressedfile);
+               gzclose(compressedfile);
+
+               /* Delete the file left behind */
+               (void)unlink(cfn);
+       }
+}
+#endif /* RLC 09 Mar 1999: End ZLIB patch */
+
 /* ----------  END FILE COMPRESSION HANDLING ----------- */
 
 
index f8d1ccdb8e6bc8a584e060476d49dc0f40cc71a5..ed118ea27ce423ed25a8a1250d73c3adf0a013d8 100644 (file)
@@ -165,6 +165,15 @@ static struct Bool_Opt
        {"rawio", (boolean *)0, FALSE, SET_IN_FILE},
 #endif
        {"rest_on_space", &flags.rest_on_space, FALSE, SET_IN_GAME},
+#ifdef RLECOMP
+       {"rlecomp", &iflags.rlecomp,
+# if defined(COMPRESS) || defined(ZLIB_COMP)
+               FALSE,
+# else
+               TRUE,
+# endif
+               DISP_IN_GAME},
+#endif
        {"safe_pet", &flags.safe_dog, TRUE, SET_IN_GAME},
 #ifdef WIZARD
        {"sanity_check", &iflags.sanity_check, FALSE, SET_IN_GAME},
@@ -206,6 +215,15 @@ static struct Bool_Opt
 #endif
        {"verbose", &flags.verbose, TRUE, SET_IN_GAME},
        {"wraptext", &iflags.wc2_wraptext, FALSE, SET_IN_GAME},
+#ifdef ZEROCOMP
+       {"zerocomp", &iflags.zerocomp,
+# if defined(COMPRESS) || defined(ZLIB_COMP)
+               FALSE,
+# else
+               TRUE,
+# endif
+               DISP_IN_GAME},
+#endif
        {(char *)0, (boolean *)0, FALSE, 0}
 };
 
@@ -515,6 +533,23 @@ initoptions()
                if (boolopt[i].addr)
                        *(boolopt[i].addr) = boolopt[i].initvalue;
        }
+#if defined(COMPRESS) || defined(ZLIB_COMP)
+       set_savepref("externalcomp");
+       set_restpref("externalcomp");
+# ifdef RLECOMP
+       set_savepref("!rlecomp");
+       set_restpref("!rlecomp");
+# endif
+#else
+# ifdef ZEROCOMP
+       set_savepref("zerocomp");
+       set_restpref("zerocomp");
+# endif
+# ifdef RLECOMP
+       set_savepref("rlecomp");
+       set_restpref("rlecomp");
+# endif
+#endif
 #ifdef SYSFLAGS
        Strcpy(sysflags.sysflagsid, "sysflags");
        sysflags.sysflagsid[9] = (char)sizeof(struct sysflag);
@@ -2328,7 +2363,22 @@ goodfruit:
 # endif
                        }
 #endif /* TERMLIB || ASCIIGRAPH || MAC_GRAPHICS_ENV */
-
+#ifdef RLECOMP
+                       if ((boolopt[i].addr) == &iflags.rlecomp) {
+                               if (*boolopt[i].addr)
+                                       set_savepref("rlecomp");
+                               else
+                                       set_savepref("!rlecomp");
+                       }
+#endif
+#ifdef ZEROCOMP
+                       if ((boolopt[i].addr) == &iflags.zerocomp) {
+                               if (*boolopt[i].addr)
+                                       set_savepref("zerocomp");
+                               else
+                                       set_savepref("externalcomp");
+                       }
+#endif
                        /* only do processing below if setting with doset() */
                        if (initial) return;
 
index cd09df5fa78d204d18de689be2e338e32a8eed1d..7d36d8e7f14f2cb783a2220454bfcbe7049669d3 100644 (file)
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)restore.c  3.5     2003/09/06      */
+/*     SCCS Id: @(#)restore.c  3.5     2005/01/04      */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -16,8 +16,14 @@ extern void FDECL(substitute_tiles, (d_level *));       /* from tile.c */
 #endif
 
 #ifdef ZEROCOMP
-static int NDECL(mgetc);
+STATIC_DCL void NDECL(zerocomp_minit);
+STATIC_DCL void FDECL(zerocomp_mread, (int,genericptr_t,unsigned int));
+STATIC_DCL int NDECL(zerocomp_mgetc);
 #endif
+
+STATIC_DCL void NDECL(def_minit);
+STATIC_DCL void FDECL(def_mread, (int,genericptr_t,unsigned int));
+
 STATIC_DCL void NDECL(find_lev_obj);
 STATIC_DCL void FDECL(restlevchn, (int));
 STATIC_DCL void FDECL(restdamage, (int,BOOLEAN_P));
@@ -34,6 +40,27 @@ STATIC_DCL void FDECL(reset_oattached_mids, (BOOLEAN_P));
 #ifndef GOLDOBJ
 STATIC_DCL struct obj *FDECL(gold_in, (struct obj *));
 #endif
+STATIC_DCL void FDECL(rest_levl, (int,BOOLEAN_P));
+
+static struct restore_procs {
+       const char *name;
+       int mread_flags;
+       void NDECL((*restore_minit));
+       void FDECL((*restore_mread), (int,genericptr_t,unsigned int));
+       void FDECL((*restore_bclose), (int));
+} restoreprocs = {
+#if !defined(ZEROCOMP) || (defined(COMPRESS) || defined(ZLIB_COMP))
+       "externalcomp", 0,
+       def_minit,
+       def_mread,
+       def_bclose,
+#else
+       "zerocomp", 0,
+       zerocomp_minit,
+       zerocomp_mread,
+       zerocomp_bclose,
+#endif
+};
 
 /*
  * Save a mapping of IDs from ghost levels to the current level.  This
@@ -547,7 +574,7 @@ xchar ltmp;
                        playwoRAMdisk();
                        /* Rewind save file and try again */
                        (void) lseek(fd, (off_t)0, 0);
-                       (void) uptodate(fd, (char *)0); /* skip version */
+                       (void) validate(fd, (char *)0); /* skip version etc */
                        return dorecover(fd);   /* 0 or 1 */
                } else {
 # endif
@@ -624,12 +651,10 @@ register int fd;
        if (strncmpi("X11", windowprocs.name, 3))
          putstr(WIN_MAP, 0, "Restoring:");
 #endif
+       restoreprocs.mread_flags = 1;   /* return despite error */
        while(1) {
-#ifdef ZEROCOMP
-               if(mread(fd, (genericptr_t) &ltmp, sizeof ltmp) < 0)
-#else
-               if(read(fd, (genericptr_t) &ltmp, sizeof ltmp) != sizeof ltmp)
-#endif
+               mread(fd, (genericptr_t) &ltmp, sizeof ltmp);
+               if (restoreprocs.mread_flags == -1)
                        break;
                getlev(fd, 0, ltmp, FALSE);
 #ifdef MICRO
@@ -646,18 +671,24 @@ register int fd;
                rtmp = restlevelfile(fd, ltmp);
                if (rtmp < 2) return(rtmp);  /* dorecover called recursively */
        }
+       restoreprocs.mread_flags = 0;
 
 #ifdef BSD
        (void) lseek(fd, 0L, 0);
 #else
        (void) lseek(fd, (off_t)0, 0);
 #endif
-       (void) uptodate(fd, (char *)0);         /* skip version info */
+       (void) validate(fd, (char *)0);         /* skip version and savefile info */
        get_plname_from_file(fd, plname);
 
        getlev(fd, 0, (xchar)0, FALSE);
        (void) close(fd);
 
+       /* Now set the restore settings to match the
+        * settings used by the save file output routines
+        */
+       reset_restpref();
+
        if (!wizard && !discover)
                (void) delete_savefile();
 #ifdef REINCARNATION
@@ -700,6 +731,41 @@ register int fd;
        return(1);
 }
 
+STATIC_OVL void
+rest_levl(fd, rlecomp)
+int fd;
+boolean rlecomp;
+{
+#ifdef RLECOMP
+       short   i, j;
+       uchar   len;
+       struct rm r;
+
+       if (rlecomp) {
+# if defined(MAC)
+               /* Suppress warning about used before set */
+               (void) memset((genericptr_t) &r, 0, sizeof(r));
+# endif
+               i = 0; j = 0; len = 0;
+               while(i < ROWNO) {
+                   while(j < COLNO) {
+                       if(len > 0) {
+                           levl[j][i] = r;
+                           len -= 1;
+                           j += 1;
+                       } else {
+                           mread(fd, (genericptr_t)&len, sizeof(uchar));
+                           mread(fd, (genericptr_t)&r, sizeof(struct rm));
+                       }
+                   }
+                   j = 0;
+                   i += 1;
+               }
+       } else
+#endif /* RLECOMP */
+       mread(fd, (genericptr_t) levl, sizeof(levl));
+}
+
 void
 trickery(reason)
 char *reason;
@@ -760,37 +826,7 @@ boolean ghostly;
 #endif
            trickery(trickbuf);
        }
-
-#ifdef RLECOMP
-       {
-               short   i, j;
-               uchar   len;
-               struct rm r;
-               
-#if defined(MAC)
-               /* Suppress warning about used before set */
-               (void) memset((genericptr_t) &r, 0, sizeof(r));
-#endif
-               i = 0; j = 0; len = 0;
-               while(i < ROWNO) {
-                   while(j < COLNO) {
-                       if(len > 0) {
-                           levl[j][i] = r;
-                           len -= 1;
-                           j += 1;
-                       } else {
-                           mread(fd, (genericptr_t)&len, sizeof(uchar));
-                           mread(fd, (genericptr_t)&r, sizeof(struct rm));
-                       }
-                   }
-                   j = 0;
-                   i += 1;
-               }
-       }
-#else
-       mread(fd, (genericptr_t) levl, sizeof(levl));
-#endif /* RLECOMP */
-
+       rest_levl(fd, (boolean)((sfrestinfo.sfi1 & SFI1_RLECOMP) == SFI1_RLECOMP));
        mread(fd, (genericptr_t)&omoves, sizeof(omoves));
        mread(fd, (genericptr_t)&upstair, sizeof(stairway));
        mread(fd, (genericptr_t)&dnstair, sizeof(stairway));
@@ -1051,6 +1087,145 @@ boolean ghostly;
 }
 
 
+void
+minit()
+{
+    (*restoreprocs.restore_minit)();
+    return;
+}
+
+void
+mread(fd, buf, len)
+register int fd;
+register genericptr_t buf;
+register unsigned int len;
+{
+    (*restoreprocs.restore_mread)(fd, buf, len);
+    return;
+}
+
+/* examine the version info and the savefile_info data
+   that immediately follows it.
+   Return 0 if it passed the checks.
+   Return 1 if it failed the version check.
+   Return 2 if it failed the savefile feature check.
+   Return -1 if it failed for some unknown reason.
+ */
+int
+validate(fd, name)
+int fd;
+const char *name;
+{
+    int rlen;
+    struct savefile_info sfi;
+    unsigned long compatible;
+    boolean verbose = name ? TRUE : FALSE, reslt = FALSE;
+
+    if (!(reslt = uptodate(fd, name))) return 1;
+
+    rlen = read(fd, (genericptr_t) &sfi, sizeof sfi);
+    minit();           /* ZEROCOMP */
+    if (rlen == 0) {
+       if (verbose) {
+           pline("File \"%s\" is empty during save file feature check?", name);
+           wait_synch();
+       }
+       return -1;
+    }
+
+    compatible = (sfi.sfi1 & sfcap.sfi1);
+
+    if ((sfi.sfi1 & SFI1_ZEROCOMP) == SFI1_ZEROCOMP) {
+       if ((compatible & SFI1_ZEROCOMP) != SFI1_ZEROCOMP) {
+           if (verbose) {
+               pline("File \"%s\" has incompatible ZEROCOMP compression.", name);
+               wait_synch();
+           }
+           return 2;
+       } else if ((sfrestinfo.sfi1 & SFI1_ZEROCOMP) != SFI1_ZEROCOMP) {
+           set_restpref("zerocomp");
+       }
+    }
+
+    if ((sfi.sfi1 & SFI1_EXTERNALCOMP) == SFI1_EXTERNALCOMP) {
+       if ((compatible & SFI1_EXTERNALCOMP) != SFI1_EXTERNALCOMP) {
+           if (verbose) {
+               pline("File \"%s\" lacks required internal compression.", name);
+               wait_synch();
+           }
+           return 2;
+       } else if ((sfrestinfo.sfi1 & SFI1_EXTERNALCOMP) != SFI1_EXTERNALCOMP) {
+           set_restpref("externalcomp");
+       }
+    }
+
+    /* RLECOMP check must be last, after ZEROCOMP or INTERNALCOMP adjustments */
+    if ((sfi.sfi1 & SFI1_RLECOMP) == SFI1_RLECOMP) {
+       if ((compatible & SFI1_RLECOMP) != SFI1_RLECOMP) {
+           if (verbose) {
+               pline("File \"%s\" has incompatible run-length compression.", name);
+               wait_synch();
+           }
+           return 2;
+       } else if ((sfrestinfo.sfi1 & SFI1_RLECOMP) != SFI1_RLECOMP) {
+           set_restpref("rlecomp");
+        }
+    }
+    /* savefile does not have RLECOMP level location compression, so adjust */
+    else set_restpref("!rlecomp");
+
+    return 0;
+}
+
+void
+reset_restpref()
+{
+#ifdef ZEROCOMP
+       if (iflags.zerocomp)
+               set_restpref("zerocomp");
+       else 
+#endif
+               set_restpref("externalcomp");
+#ifdef RLECOMP
+       if (iflags.rlecomp)
+               set_restpref("rlecomp");
+       else
+#endif
+               set_restpref("!rlecomp");
+}
+
+void
+set_restpref(suitename)
+const char *suitename;
+{
+       if (!strcmpi(suitename, "externalcomp")) {
+               restoreprocs.name = "externalcomp";
+               restoreprocs.restore_mread = def_mread;
+               restoreprocs.restore_minit = def_minit;
+               sfrestinfo.sfi1 |= SFI1_EXTERNALCOMP;
+               sfrestinfo.sfi1 &= ~SFI1_ZEROCOMP;
+               def_minit();
+       }
+       if (!strcmpi(suitename, "!rlecomp")) {
+               sfrestinfo.sfi1 &= ~SFI1_RLECOMP;
+       }
+#ifdef ZEROCOMP
+       if (!strcmpi(suitename, "zerocomp")) {
+               restoreprocs.name = "zerocomp";
+               restoreprocs.restore_mread = zerocomp_mread;
+               restoreprocs.restore_minit = zerocomp_minit;
+               sfrestinfo.sfi1 |= SFI1_ZEROCOMP;
+               sfrestinfo.sfi1 &= ~SFI1_EXTERNALCOMP;
+               zerocomp_minit();
+       }
+#endif
+#ifdef RLECOMP
+       if (!strcmpi(suitename, "rlecomp")) {
+               sfrestinfo.sfi1 |= SFI1_RLECOMP;
+       }
+#endif
+}
+
 #ifdef ZEROCOMP
 #define RLESC '\0'     /* Leading character for run of RLESC's */
 
@@ -1063,8 +1238,8 @@ static NEARDATA unsigned short inbufsz = 0;
 static NEARDATA short inrunlength = -1;
 static NEARDATA int mreadfd;
 
-static int
-mgetc()
+STATIC_OVL int
+zerocomp_mgetc()
 {
     if (inbufp >= inbufsz) {
        inbufsz = read(mreadfd, (genericptr_t)inbuf, sizeof inbuf);
@@ -1079,16 +1254,16 @@ mgetc()
     return inbuf[inbufp++];
 }
 
-void
-minit()
+STATIC_OVL void
+zerocomp_minit()
 {
     inbufsz = 0;
     inbufp = 0;
     inrunlength = -1;
 }
 
-int
-mread(fd, buf, len)
+STATIC_OVL void
+zerocomp_mread(fd, buf, len)
 int fd;
 genericptr_t buf;
 register unsigned len;
@@ -1101,27 +1276,28 @@ register unsigned len;
            inrunlength--;
            *(*((char **)&buf))++ = '\0';
        } else {
-           register short ch = mgetc();
-           if (ch < 0) return -1; /*readlen;*/
+           register short ch = zerocomp_mgetc();
+           if (ch < 0) {
+               restoreprocs.mread_flags = -1;
+               return;
+           }
            if ((*(*(char **)&buf)++ = (char)ch) == RLESC) {
-               inrunlength = mgetc();
+               inrunlength = zerocomp_mgetc();
            }
        }
        /*readlen++;*/
     }
-    return 0; /*readlen;*/
 }
+#endif /* ZEROCOMP */
 
-#else /* ZEROCOMP */
-
-void
-minit()
+STATIC_OVL void
+def_minit()
 {
     return;
 }
 
-void
-mread(fd, buf, len)
+STATIC_OVL void
+def_mread(fd, buf, len)
 register int fd;
 register genericptr_t buf;
 register unsigned int len;
@@ -1135,6 +1311,10 @@ register unsigned int len;
        rlen = read(fd, buf, (unsigned) len);
        if((unsigned)rlen != len){
 #endif
+           if (restoreprocs.mread_flags == 1) { /* means "return anyway" */
+               restoreprocs.mread_flags = -1;
+               return;
+           } else {
                pline("Read %d instead of %u bytes.", rlen, len);
                if(restoring) {
                        (void) close(fd);
@@ -1142,9 +1322,10 @@ register unsigned int len;
                        error("Error restoring old game.");
                }
                panic("Error reading level file.");
+           }
        }
 }
-#endif /* ZEROCOMP */
+
 #ifndef GOLDOBJ
 /*
  * Takes all of the gold objects out of the invent or
index a5519b8079c2fbf1b3c6052840bdaa2ac0564091..9477eacee295bdbd548aef0844696496410fe81e 100644 (file)
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)save.c     3.5     2003/11/14      */
+/*     SCCS Id: @(#)save.c     3.5     2005/01/04      */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -22,9 +22,6 @@ static int count_only;
 int dotcnt, dotrow;    /* also used in restore */
 #endif
 
-#ifdef ZEROCOMP
-STATIC_DCL void FDECL(bputc, (int));
-#endif
 STATIC_DCL void FDECL(savelevchn, (int,int));
 STATIC_DCL void FDECL(savedamage, (int,int));
 STATIC_DCL void FDECL(saveobjchn, (int,struct obj *,int));
@@ -37,6 +34,44 @@ STATIC_DCL void FDECL(savelev0, (int,XCHAR_P,int));
 STATIC_DCL boolean NDECL(swapout_oldest);
 STATIC_DCL void FDECL(copyfile, (char *,char *));
 #endif /* MFLOPPY */
+STATIC_DCL void FDECL(savelevl, (int fd, BOOLEAN_P));
+STATIC_DCL void FDECL(def_bufon, (int));
+STATIC_DCL void FDECL(def_bufoff, (int));
+STATIC_DCL void FDECL(def_bflush, (int));
+STATIC_DCL void FDECL(def_bwrite, (int,genericptr_t,unsigned int));
+#ifdef ZEROCOMP
+STATIC_DCL void FDECL(zerocomp_bufon, (int));
+STATIC_DCL void FDECL(zerocomp_bufoff, (int));
+STATIC_DCL void FDECL(zerocomp_bflush, (int));
+STATIC_DCL void FDECL(zerocomp_bwrite, (int,genericptr_t,unsigned int));
+STATIC_DCL void FDECL(zerocomp_bputc, (int));
+#endif
+
+static struct save_procs {
+       const char *name;
+       void FDECL((*save_bufon), (int));
+       void FDECL((*save_bufoff), (int));
+       void FDECL((*save_bflush), (int));
+       void FDECL((*save_bwrite), (int,genericptr_t,unsigned int));
+       void FDECL((*save_bclose), (int));
+} saveprocs = {
+#if !defined(ZEROCOMP) || (defined(COMPRESS) || defined(ZLIB_COMP))
+       "externalcomp",
+       def_bufon,
+       def_bufoff,
+       def_bflush,
+       def_bwrite,
+       def_bclose,
+#else
+       "zerocomp",
+       zerocomp_bufon,
+       zerocomp_bufoff,
+       zerocomp_bflush,
+       zerocomp_bwrite,
+       zerocomp_bclose,
+#endif
+};
+
 #ifdef GCC_WARN
 static long nulls[10];
 #else
@@ -140,14 +175,14 @@ dosave0()
 #endif
 
        HUP if (iflags.window_inited) {
-           uncompress(fq_save);
+           nh_uncompress(fq_save);
            fd = open_savefile();
            if (fd > 0) {
                (void) close(fd);
                clear_nhwindow(WIN_MESSAGE);
                There("seems to be an old save file.");
                if (yn("Overwrite the old file?") == 'n') {
-                   compress(fq_save);
+                   nh_compress(fq_save);
                    return 0;
                }
            }
@@ -209,6 +244,7 @@ dosave0()
 #endif /* MFLOPPY */
 
        store_version(fd);
+       store_savefileinfo(fd);
        store_plname_in_file(fd);
        ustuck_id = (u.ustuck ? u.ustuck->m_id : 0);
 #ifdef STEED
@@ -269,7 +305,7 @@ dosave0()
        /* get rid of current level --jgm */
        delete_levelfile(ledger_no(&u.uz));
        delete_levelfile(0);
-       compress(fq_save);
+       nh_compress(fq_save);
        return(1);
 }
 
@@ -405,6 +441,7 @@ savestateinlock()
                    (void) write(fd, (genericptr_t) &currlev, sizeof(currlev));
                    save_savefile_name(fd);
                    store_version(fd);
+                   store_savefileinfo(fd);
                    store_plname_in_file(fd);
 
                    ustuck_id = (u.ustuck ? u.ustuck->m_id : 0);
@@ -489,12 +526,57 @@ int mode;
 #else
        bwrite(fd,(genericptr_t) &lev,sizeof(lev));
 #endif
+       savelevl(fd, (boolean)((sfsaveinfo.sfi1 & SFI1_RLECOMP) == SFI1_RLECOMP));
+
+       bwrite(fd,(genericptr_t) &monstermoves,sizeof(monstermoves));
+       bwrite(fd,(genericptr_t) &upstair,sizeof(stairway));
+       bwrite(fd,(genericptr_t) &dnstair,sizeof(stairway));
+       bwrite(fd,(genericptr_t) &upladder,sizeof(stairway));
+       bwrite(fd,(genericptr_t) &dnladder,sizeof(stairway));
+       bwrite(fd,(genericptr_t) &sstairs,sizeof(stairway));
+       bwrite(fd,(genericptr_t) &updest,sizeof(dest_area));
+       bwrite(fd,(genericptr_t) &dndest,sizeof(dest_area));
+       bwrite(fd,(genericptr_t) &level.flags,sizeof(level.flags));
+       bwrite(fd, (genericptr_t) doors, sizeof(doors));
+       save_rooms(fd); /* no dynamic memory to reclaim */
+
+       /* from here on out, saving also involves allocated memory cleanup */
+ skip_lots:
+       /* must be saved before mons, objs, and buried objs */
+       save_timers(fd, mode, RANGE_LEVEL);
+       save_light_sources(fd, mode, RANGE_LEVEL);
+
+       savemonchn(fd, fmon, mode);
+       save_worm(fd, mode);    /* save worm information */
+       savetrapchn(fd, ftrap, mode);
+       saveobjchn(fd, fobj, mode);
+       saveobjchn(fd, level.buriedobjlist, mode);
+       saveobjchn(fd, billobjs, mode);
+       if (release_data(mode)) {
+           fmon = 0;
+           ftrap = 0;
+           fobj = 0;
+           level.buriedobjlist = 0;
+           billobjs = 0;
+       }
+       save_engravings(fd, mode);
+       savedamage(fd, mode);
+       save_regions(fd, mode);
+       if (mode != FREE_SAVE) bflush(fd);
+}
+
+STATIC_OVL void
+savelevl(fd, rlecomp)
+int fd;
+boolean rlecomp;
+{
 #ifdef RLECOMP
-       {
+       struct rm *prm, *rgrm;
+       int x, y;
+       uchar match;
+
+       if (rlecomp) {
            /* perform run-length encoding of rm structs */
-           struct rm *prm, *rgrm;
-           int x, y;
-           uchar match;
 
            rgrm = &levl[0][0];         /* start matching at first rm */
            match = 0;
@@ -533,46 +615,150 @@ int mode;
                bwrite(fd, (genericptr_t)&match, sizeof(uchar));
                bwrite(fd, (genericptr_t)rgrm, sizeof(struct rm));
            }
-       }
-#else
-       bwrite(fd,(genericptr_t) levl,sizeof(levl));
+       } else
 #endif /* RLECOMP */
+       bwrite(fd,(genericptr_t) levl,sizeof(levl));
+}
 
-       bwrite(fd,(genericptr_t) &monstermoves,sizeof(monstermoves));
-       bwrite(fd,(genericptr_t) &upstair,sizeof(stairway));
-       bwrite(fd,(genericptr_t) &dnstair,sizeof(stairway));
-       bwrite(fd,(genericptr_t) &upladder,sizeof(stairway));
-       bwrite(fd,(genericptr_t) &dnladder,sizeof(stairway));
-       bwrite(fd,(genericptr_t) &sstairs,sizeof(stairway));
-       bwrite(fd,(genericptr_t) &updest,sizeof(dest_area));
-       bwrite(fd,(genericptr_t) &dndest,sizeof(dest_area));
-       bwrite(fd,(genericptr_t) &level.flags,sizeof(level.flags));
-       bwrite(fd, (genericptr_t) doors, sizeof(doors));
-       save_rooms(fd); /* no dynamic memory to reclaim */
+/*ARGSUSED*/
+void
+bufon(fd)
+int fd;
+{
+    (*saveprocs.save_bufon)(fd);
+    return;
+}
 
-       /* from here on out, saving also involves allocated memory cleanup */
- skip_lots:
-       /* must be saved before mons, objs, and buried objs */
-       save_timers(fd, mode, RANGE_LEVEL);
-       save_light_sources(fd, mode, RANGE_LEVEL);
+/*ARGSUSED*/
+void
+bufoff(fd)
+int fd;
+{
+    (*saveprocs.save_bufoff)(fd);
+    return;
+}
 
-       savemonchn(fd, fmon, mode);
-       save_worm(fd, mode);    /* save worm information */
-       savetrapchn(fd, ftrap, mode);
-       saveobjchn(fd, fobj, mode);
-       saveobjchn(fd, level.buriedobjlist, mode);
-       saveobjchn(fd, billobjs, mode);
-       if (release_data(mode)) {
-           fmon = 0;
-           ftrap = 0;
-           fobj = 0;
-           level.buriedobjlist = 0;
-           billobjs = 0;
+void
+bflush(fd)  /* flush run and buffer */
+register int fd;
+{
+    (*saveprocs.save_bflush)(fd);
+    return;
+}
+
+void
+bwrite(fd, loc, num)
+int fd;
+genericptr_t loc;
+register unsigned num;
+{
+    (*saveprocs.save_bwrite)(fd, loc, num);
+    return;
+}
+
+void
+bclose(fd)
+int fd;
+{
+    (*saveprocs.save_bclose)(fd);
+    return;
+}
+
+static int bw_fd = -1;
+static FILE *bw_FILE = 0;
+static boolean buffering = FALSE;
+
+STATIC_OVL void
+def_bufon(fd)
+    int fd;
+{
+#ifdef UNIX
+    if(bw_fd != fd) {
+       if(bw_fd >= 0)
+           panic("double buffering unexpected");
+       bw_fd = fd;
+       if((bw_FILE = fdopen(fd, "w")) == 0)
+           panic("buffering of file %d failed", fd);
+    }
+#endif
+    buffering = TRUE;
+}
+
+STATIC_OVL void
+def_bufoff(fd)
+int fd;
+{
+    def_bflush(fd);
+    buffering = FALSE;
+}
+
+STATIC_OVL void
+def_bflush(fd)
+    int fd;
+{
+#ifdef UNIX
+    if(fd == bw_fd) {
+       if(fflush(bw_FILE) == EOF)
+           panic("flush of savefile failed!");
+    }
+#endif
+    return;
+}
+
+STATIC_OVL void
+def_bwrite(fd,loc,num)
+register int fd;
+register genericptr_t loc;
+register unsigned num;
+{
+       boolean failed;
+
+#ifdef MFLOPPY
+       bytes_counted += num;
+       if (count_only) return;
+#endif
+
+#ifdef UNIX
+       if (buffering) {
+           if(fd != bw_fd)
+               panic("unbuffered write to fd %d (!= %d)", fd, bw_fd);
+
+           failed = (fwrite(loc, (int)num, 1, bw_FILE) != 1);
+       } else
+#endif /* UNIX */
+       {
+/* lint wants the 3rd arg of write to be an int; lint -p an unsigned */
+#if defined(BSD) || defined(ULTRIX) || defined(WIN32)
+           failed = (write(fd, loc, (int)num) != (int)num);
+#else /* e.g. SYSV, __TURBOC__ */
+           failed = (write(fd, loc, num) != num);
+#endif
+       }
+
+       if (failed) {
+#if defined(UNIX) || defined(VMS) || defined(__EMX__)
+           if (program_state.done_hup)
+               terminate(EXIT_FAILURE);
+           else
+#endif
+               panic("cannot write %u bytes to file #%d", num, fd);
        }
-       save_engravings(fd, mode);
-       savedamage(fd, mode);
-       save_regions(fd, mode);
-       if (mode != FREE_SAVE) bflush(fd);
+}
+
+void
+def_bclose(fd)
+    int fd;
+{
+    bufoff(fd);
+#ifdef UNIX
+    if (fd == bw_fd) {
+       (void) fclose(bw_FILE);
+       bw_fd = -1;
+       bw_FILE = 0;
+    } else
+#endif
+       (void) close(fd);
+    return;
 }
 
 #ifdef ZEROCOMP
@@ -585,7 +771,7 @@ int mode;
  */
 
 #define RLESC '\0'    /* Leading character for run of LRESC's */
-#define flushoutrun(ln) (bputc(RLESC), bputc(ln), ln = -1)
+#define flushoutrun(ln) (zerocomp_bputc(RLESC), zerocomp_bputc(ln), ln = -1)
 
 #ifndef ZEROCOMP_BUFSIZ
 # define ZEROCOMP_BUFSIZ BUFSZ
@@ -602,7 +788,7 @@ static NEARDATA boolean compressing = FALSE;
 }*/
 
 STATIC_OVL void
-bputc(c)
+zerocomp_bputc(c)
 int c;
 {
 #ifdef MFLOPPY
@@ -619,7 +805,7 @@ int c;
 
 /*ARGSUSED*/
 void
-bufon(fd)
+STATIC_OVL zerocomp_bufon(fd)
 int fd;
 {
     compressing = TRUE;
@@ -627,8 +813,8 @@ int fd;
 }
 
 /*ARGSUSED*/
-void
-bufoff(fd)
+STATIC_OVL void
+zerocomp_bufoff(fd)
 int fd;
 {
     if (outbufp) {
@@ -640,8 +826,8 @@ int fd;
     return;
 }
 
-void
-bflush(fd)  /* flush run and buffer */
+STATIC_OVL void
+zerocomp_bflush(fd)  /* flush run and buffer */
 register int fd;
 {
     bwritefd = fd;
@@ -659,14 +845,14 @@ register int fd;
                terminate(EXIT_FAILURE);
            else
 #endif
-               bclose(fd);     /* panic (outbufp != 0) */
+               zerocomp_bclose(fd);    /* panic (outbufp != 0) */
        }
        outbufp = 0;
     }
 }
 
-void
-bwrite(fd, loc, num)
+STATIC_OVL void
+zerocomp_bwrite(fd, loc, num)
 int fd;
 genericptr_t loc;
 register unsigned num;
@@ -697,119 +883,20 @@ register unsigned num;
                if (outrunlength >= 0) {        /* flush run */
                    flushoutrun(outrunlength);
                }
-               bputc(*bp);
+               zerocomp_bputc(*bp);
            }
        }
     }
 }
 
 void
-bclose(fd)
+zerocomp_bclose(fd)
 int fd;
 {
-    bufoff(fd);
+    zerocomp_bufoff(fd);
     (void) close(fd);
     return;
 }
-
-#else /* ZEROCOMP */
-
-static int bw_fd = -1;
-static FILE *bw_FILE = 0;
-static boolean buffering = FALSE;
-
-void
-bufon(fd)
-    int fd;
-{
-#ifdef UNIX
-    if(bw_fd != fd) {
-       if(bw_fd >= 0)
-           panic("double buffering unexpected");
-       bw_fd = fd;
-       if((bw_FILE = fdopen(fd, "w")) == 0)
-           panic("buffering of file %d failed", fd);
-    }
-#endif
-    buffering = TRUE;
-}
-
-void
-bufoff(fd)
-int fd;
-{
-    bflush(fd);
-    buffering = FALSE;
-}
-
-void
-bflush(fd)
-    int fd;
-{
-#ifdef UNIX
-    if(fd == bw_fd) {
-       if(fflush(bw_FILE) == EOF)
-           panic("flush of savefile failed!");
-    }
-#endif
-    return;
-}
-
-void
-bwrite(fd,loc,num)
-register int fd;
-register genericptr_t loc;
-register unsigned num;
-{
-       boolean failed;
-
-#ifdef MFLOPPY
-       bytes_counted += num;
-       if (count_only) return;
-#endif
-
-#ifdef UNIX
-       if (buffering) {
-           if(fd != bw_fd)
-               panic("unbuffered write to fd %d (!= %d)", fd, bw_fd);
-
-           failed = (fwrite(loc, (int)num, 1, bw_FILE) != 1);
-       } else
-#endif /* UNIX */
-       {
-/* lint wants the 3rd arg of write to be an int; lint -p an unsigned */
-#if defined(BSD) || defined(ULTRIX)
-           failed = (write(fd, loc, (int)num) != (int)num);
-#else /* e.g. SYSV, __TURBOC__ */
-           failed = (write(fd, loc, num) != num);
-#endif
-       }
-
-       if (failed) {
-#if defined(UNIX) || defined(VMS) || defined(__EMX__)
-           if (program_state.done_hup)
-               terminate(EXIT_FAILURE);
-           else
-#endif
-               panic("cannot write %u bytes to file #%d", num, fd);
-       }
-}
-
-void
-bclose(fd)
-    int fd;
-{
-    bufoff(fd);
-#ifdef UNIX
-    if (fd == bw_fd) {
-       (void) fclose(bw_FILE);
-       bw_fd = -1;
-       bw_FILE = 0;
-    } else
-#endif
-       (void) close(fd);
-    return;
-}
 #endif /* ZEROCOMP */
 
 STATIC_OVL void
@@ -1048,6 +1135,65 @@ register int fd, mode;
        pline("Stored %d messages into savefile.", msgcount);
 #endif
 }
+
+void
+store_savefileinfo(fd)
+int fd;
+{
+       /* sfcap (decl.c) describes the savefile feature capabilities
+        * that are supported by this port/platform build.
+        * 
+        * sfsaveinfo (decl.c) describes the savefile info that actually
+        * gets written into the savefile, and is used to determine the
+        * save file being written.
+
+        * sfrestinfo (decl.c) describes the savefile info that is
+        * being used to read the information from an existing savefile.
+        *
+        */
+
+       bufoff(fd);
+       /* bwrite() before bufon() uses plain write() */
+       bwrite(fd,(genericptr_t)&sfsaveinfo, (unsigned)(sizeof sfsaveinfo));
+       bufon(fd);
+       return;
+}
+
+void
+set_savepref(suitename)
+const char *suitename;
+{
+       if (!strcmpi(suitename, "externalcomp")) {
+               saveprocs.name = "externalcomp";
+               saveprocs.save_bufon = def_bufon;
+               saveprocs.save_bufoff = def_bufoff;
+               saveprocs.save_bflush = def_bflush;
+               saveprocs.save_bwrite = def_bwrite;
+               saveprocs.save_bclose = def_bclose;
+               sfsaveinfo.sfi1 |= SFI1_EXTERNALCOMP;
+               sfsaveinfo.sfi1 &= ~SFI1_ZEROCOMP;
+       }
+       if (!strcmpi(suitename, "!rlecomp")) {
+               sfsaveinfo.sfi1 &= ~SFI1_RLECOMP;
+       }
+#ifdef ZEROCOMP
+       if (!strcmpi(suitename, "zerocomp")) {
+               saveprocs.name = "zerocomp";
+               saveprocs.save_bufon = zerocomp_bufon;
+               saveprocs.save_bufoff = zerocomp_bufoff;
+               saveprocs.save_bflush = zerocomp_bflush;
+               saveprocs.save_bwrite = zerocomp_bwrite;
+               saveprocs.save_bclose = zerocomp_bclose;
+               sfsaveinfo.sfi1 |= SFI1_ZEROCOMP;
+               sfsaveinfo.sfi1 &= ~SFI1_EXTERNALCOMP;
+       }
+#endif
+#ifdef RLECOMP
+       if (!strcmpi(suitename, "rlecomp")) {
+               sfsaveinfo.sfi1 |= SFI1_RLECOMP;
+       }
+#endif
+}
        
 /* also called by prscore(); this probably belongs in dungeon.c... */
 void
index d277fcdca2c227ca1845e347ed192874bd4ed802..4c077be4f6a8d4205955662770c9c67f36aa6682 100644 (file)
@@ -106,7 +106,7 @@ int MAIN(int argc, char **argv)
                        if(yn("Do you want to keep the save file?") == 'n')
                            (void) delete_savefile();
                        else {
-                           compress(fqname(SAVEF, SAVEPREFIX, 0));
+                           nh_compress(fqname(SAVEF, SAVEPREFIX, 0));
                        }
                }
 
index fe57051308e77e858766170684b57b3660bef960..5d91a139e43cd362338aea3561dcbe8ad73b9e74 100644 (file)
@@ -117,7 +117,7 @@ main (void)
                                if(yn("Do you want to keep the save file?") == 'n')
                                        (void) delete_savefile();
                                else {
-                                       compress(fqname(SAVEF, SAVEPREFIX, 0));
+                                       nh_compress(fqname(SAVEF, SAVEPREFIX, 0));
                                }
                        }
                }
index eca498128b78d13d698975d5295a6d451ca55318..b345a8fba8131cb72fb5865601a92bb2e529e7c0 100644 (file)
@@ -423,9 +423,12 @@ char *argv[];
                update_inventory();
 
                if (discover || wizard) {
-                       if(yn("Do you want to keep the save file?") == 'n'){
+                       if(yn("Do you want to keep the save file?") == 'n')
                                (void) delete_savefile();
+                       else {
+                           nh_compress(fqname(SAVEF, SAVEPREFIX, 0));
                        }
+
                }
 
                context.move = 0;
index 537b265295b0d6383ee13e51394e7d3ae6598f79..4272564287aa6264c716878711e4ee1118abaa79 100644 (file)
@@ -282,6 +282,9 @@ WINLIB = $(WINTTYLIB)
 # IRIX 4.0.x needs -lsun if NIS (YP) is being used for passwd file lookup
 # LIBS = -lsun
 #
+# If ZLIB_COMP is defined in config.h this is necessary to link with zlib.
+# LIBS = -lz
+#
 LIBS =
 
 # make NetHack
index 4ec7a602153ee748a40bb8841516fb160922cc91..11f7a93199271c05134b2effce18a16768c4dbd2 100644 (file)
@@ -287,7 +287,7 @@ char *argv[];
                            (void) delete_savefile();
                        else {
                            (void) chmod(fq_save,FCMASK); /* back to readable */
-                           compress(fq_save);
+                           nh_compress(fq_save);
                        }
                }
                context.move = 0;
index 5e0c7652cfa1d8104fc51a54fcc78dab10d33dcc..b8908bbc2c2e117ec5ba5f2199bf5e8bb4cf2a6d 100644 (file)
@@ -1,5 +1,5 @@
 #       SCCS Id: @(#)Makefile.msc       3.5     $Date$
-#       Copyright (c) NetHack PC Development Team 1993-2003
+#       Copyright (c) NetHack PC Development Team 1993-2005
 #
 #       NetHack 3.5.x Makefile for MS Visual C++ V6.x and above and MS NMAKE
 #  
@@ -127,6 +127,15 @@ RANDOM     = $(OBJ)\random.o
 
 PRECOMPHEAD = N                        # set to Y if you want to use precomp. headers
 
+#
+# If you defined ZLIB_COMP in include/config.h and you need
+# to link with the zlib.lib library, uncomment the line below.
+# If necessary, prefix explicit path information to the file name
+# otherwise it assumes the NetHack src directory.
+#
+
+#ZLIB = zlib.lib
+
 #===============================================
 #======= End of Modification Section ===========
 #===============================================
@@ -578,7 +587,7 @@ $(NHRES): $(NTSYS)\console.rc $(NTSYS)\NetHack.ico
 $(GAMEFILE) : $(ALLOBJ) $(NHRES) $(O)gamedir.tag $(WINDLLS)
        @if not exist $(GAMEDIR)\*.* mkdir $(GAMEDIR)
        @echo Linking....
-       $(link) $(LFLAGS) user32.lib winmm.lib -out:$@ @<<$(GAME).lnk
+       $(link) $(LFLAGS) $(ZLIB) user32.lib winmm.lib -out:$@ @<<$(GAME).lnk
                $(ALLOBJ:^      =^
                ) $(NHRES)
 <<
index 5e5f1ffa6e747c34461d05fb6276c1a3a1efcc00..4b04f0908ea73f1271d62d6f01ced8cdf6b21228 100644 (file)
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)makedefs.c 3.5     2002/08/14      */
+/*     SCCS Id: @(#)makedefs.c 3.5     2005/01/04      */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* Copyright (c) M. Stephenson, 1990, 1991.                      */
 /* Copyright (c) Dean Luick, 1990.                               */
@@ -411,11 +411,24 @@ do_rumors()
 
 /*
  * Use this to explicitly mask out features during version checks.
+ *
+ * ZEROCOMP, RLECOMP, and ZLIB_COMP describe compression features
+ * that the port/plaform which wrote the savefile was capable of
+ * dealing with. Don't reject a savefile just because the port
+ * reading the savefile doesn't match on all/some of them.
+ * The actual compression features used to produce the savefile are
+ * recorded in the savefile_info structure immediately following the
+ * version_info, and that is what needs to be checked against the
+ * feature set of the port that is reading the savefile back in.
+ * That check is done in src/restore.c now.
+ * 
  */
 #define IGNORED_FEATURES       ( 0L \
                                | (1L << 12)    /* GOLDOBJ */ \
                                | (1L << 20)    /* EXP_ON_BOTL */ \
                                | (1L << 21)    /* SCORE_ON_BOTL */ \
+                               | (1L << 27)    /* ZEROCOMP */ \
+                               | (1L << 28)    /* RLECOMP */ \
                                )
 
 static void
@@ -478,7 +491,9 @@ make_version()
 #ifdef SCORE_ON_BOTL
                        | (1L << 21)
 #endif
-               /* data format [COMPRESS excluded] (27..31) */
+               /* data format (27..31)
+                * External compression methods such as COMPRESS and ZLIB_COMP
+                * do not affect the contents and are thus excluded from here */
 #ifdef ZEROCOMP
                        | (1L << 27)
 #endif
@@ -653,6 +668,9 @@ static const char *build_opts[] = {
 #ifdef COMPRESS
                "data file compression",
 #endif
+#ifdef ZLIB_COMP
+               "ZLIB data file compression",
+#endif
 #ifdef DLB
                "data librarian",
 #endif
@@ -783,6 +801,9 @@ static const char *build_opts[] = {
 #endif
 #ifdef ZEROCOMP
                "zero-compressed save files",
+#endif
+#ifdef RLECOMP
+               "run-length compression of levl array in save files",
 #endif
                save_bones_compat_buf,
                "basic NetHack features"