zlib support; also internal compression changes

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.
This commit is contained in:
nethack.allison
2005-01-22 15:28:15 +00:00
parent c40d876c3b
commit ab1872b928
20 changed files with 982 additions and 263 deletions

View 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') {

View 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()

View 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 ----------- */

View 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;

View 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

View 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,54 +526,7 @@ int mode;
#else
bwrite(fd,(genericptr_t) &lev,sizeof(lev));
#endif
#ifdef 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;
for (y = 0; y < ROWNO; y++) {
for (x = 0; x < COLNO; x++) {
prm = &levl[x][y];
if (prm->glyph == rgrm->glyph
&& prm->typ == rgrm->typ
&& prm->seenv == rgrm->seenv
&& prm->horizontal == rgrm->horizontal
&& prm->flags == rgrm->flags
&& prm->lit == rgrm->lit
&& prm->waslit == rgrm->waslit
&& prm->roomno == rgrm->roomno
&& prm->edge == rgrm->edge) {
match++;
if (match > 254) {
match = 254; /* undo this match */
goto writeout;
}
} else {
/* the run has been broken,
* write out run-length encoding */
writeout:
bwrite(fd, (genericptr_t)&match, sizeof(uchar));
bwrite(fd, (genericptr_t)rgrm, sizeof(struct rm));
/* start encoding again. we have at least 1 rm
* in the next run, viz. this one. */
match = 1;
rgrm = prm;
}
}
}
if (match > 0) {
bwrite(fd, (genericptr_t)&match, sizeof(uchar));
bwrite(fd, (genericptr_t)rgrm, sizeof(struct rm));
}
}
#else
bwrite(fd,(genericptr_t) levl,sizeof(levl));
#endif /* RLECOMP */
savelevl(fd, (boolean)((sfsaveinfo.sfi1 & SFI1_RLECOMP) == SFI1_RLECOMP));
bwrite(fd,(genericptr_t) &monstermoves,sizeof(monstermoves));
bwrite(fd,(genericptr_t) &upstair,sizeof(stairway));
@@ -575,6 +565,202 @@ int 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 */
rgrm = &levl[0][0]; /* start matching at first rm */
match = 0;
for (y = 0; y < ROWNO; y++) {
for (x = 0; x < COLNO; x++) {
prm = &levl[x][y];
if (prm->glyph == rgrm->glyph
&& prm->typ == rgrm->typ
&& prm->seenv == rgrm->seenv
&& prm->horizontal == rgrm->horizontal
&& prm->flags == rgrm->flags
&& prm->lit == rgrm->lit
&& prm->waslit == rgrm->waslit
&& prm->roomno == rgrm->roomno
&& prm->edge == rgrm->edge) {
match++;
if (match > 254) {
match = 254; /* undo this match */
goto writeout;
}
} else {
/* the run has been broken,
* write out run-length encoding */
writeout:
bwrite(fd, (genericptr_t)&match, sizeof(uchar));
bwrite(fd, (genericptr_t)rgrm, sizeof(struct rm));
/* start encoding again. we have at least 1 rm
* in the next run, viz. this one. */
match = 1;
rgrm = prm;
}
}
}
if (match > 0) {
bwrite(fd, (genericptr_t)&match, sizeof(uchar));
bwrite(fd, (genericptr_t)rgrm, sizeof(struct rm));
}
} else
#endif /* RLECOMP */
bwrite(fd,(genericptr_t) levl,sizeof(levl));
}
/*ARGSUSED*/
void
bufon(fd)
int fd;
{
(*saveprocs.save_bufon)(fd);
return;
}
/*ARGSUSED*/
void
bufoff(fd)
int fd;
{
(*saveprocs.save_bufoff)(fd);
return;
}
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);
}
}
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
/* The runs of zero-run compression are flushed after the game state or a
* level is written out. This adds a couple bytes to a save file, where
@@ -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