freedink-109.6/0000755000175000017500000000000013432116467010330 500000000000000freedink-109.6/BUILD0000644000175000017500000001500713420460775011036 00000000000000Instructions to build from scratch (from the repository sources). If you downloaded a release you can skip the "Bootstrap" instructions and go to "Dependencies" directly. These instructions may sound redundant with the packaging specs (.deb, .rpm, .ebuild, etc.) but they are necessary for people who want to compile the latest, not-yet-packaged sources :) On a minimal Debian system ========================== ## Bootstrap # Source code: apt-get install git git clone git://git.sv.gnu.org/freedink cd freedink/ # Gnulib (cd /usr/src && git clone git://git.sv.gnu.org/gnulib) # or: #apt-get install gnulib # autoconf automake: base autotools # pkg-config: for PKG_CHECK_MODULES # help2man: to rebuild manpages # gettext autopoint: for i18n # rsync: to fetch translationproject.org apt-get install autoconf automake pkg-config help2man gettext autopoint rsync sh bootstrap ## Dependencies # Base: GCC, make & al. apt-get install build-essential # Required: libraries apt-get install pkg-config \ libsdl2-dev \ libsdl2-image-dev libsdl2-image-dbg \ libsdl2-mixer-dev libsdl2-mixer-dbg \ libsdl2-ttf-dev libsdl2-ttf-dbg \ libsdl2-gfx-dev libsdl2-gfx-dbg \ libfontconfig1-dev \ libglm-dev \ cxxtest # Optional: # - upx compresses binary # - bzip is for .tar.bz2 release tarballs apt-get install upx-ucl bzip2 ## Compilation ./configure make make install ## Release tests make dist make distcheck ## Optional: software MIDI support, used by SDL_mixer # Check doc/midi.txt for details apt-get install timidity freepats # :) On a minimal Fedora system ========================== (use 'yum' or 'pkcon' indifferently) ## Bootstrap # Source code: yum install git-core git clone git://git.sv.gnu.org/freedink cd freedink/ # Gnulib (cd /usr/src && git clone git://git.sv.gnu.org/gnulib) # No Fedora package, but there's no need for one. # autoconf automake: base autotools # pkg-config: for PKG_CHECK_MODULES # help2man: to rebuild manpages # gettext autpoint: for i18n # rsync: to fetch translationproject.org yum install autoconf automake pkg-config help2man gettext-devel rsync sh bootstrap ## Dependencies # Base: GCC, make & al. yum groupinstall 'Development Tools' # or just: #yum install make gcc-c++ yum install SDL2-devel \ SDL2_gfx-devel SDL2_ttf-devel SDL2_image-devel SDL2_mixer-devel \ fontconfig-devel glm-devel # Optional: # - upx compresses binary # - bzip is for .tar.bz2 release tarballs yum install upx bzip2 ## Compilation ./configure make make install ## Release tests make dist make distcheck ## Optional: software MIDI support, used by SDL_mixer # Check doc/sound.txt for details # timidity++ and timidity++-patches already installed as dependencies # from SDL_mixer # :) On a minimal Gentoo system ========================== ## Bootstrap # Source code: emerge dev-util/git git clone git://git.sv.gnu.org/freedink cd freedink # Gnulib (cd /usr/src && git clone git://git.sv.gnu.org/gnulib) # or: # Gnulib is currently masked, you need to unmask it: # http://gentoo-wiki.com/Masked#Masked_by_missing_keyword # Not that there are issues with the Gentoo wrapper. Use # /usr/share/gnulib/gnulib-tool instead of /usr/bin/gnulib-tool if # possible #echo "dev-libs/gnulib **" >> /etc/portage/package.keywords #emerge gnulib # I assume you already have autoconf & al. ;) emerge help2man # to rebuild manpages emerge pkgconfig # for PKG_CHECK_MODULES sh bootstrap ## Dependencies # I also assume you already have GCC and Make ;) emerge libsdl # (if not already done in bootstrap step) emerge sdl-gfx sdl-ttf sdl-image sdl-mixer fontconfig # Optional: # - upx compresses binary # - bzip is for .tar.bz2 release tarballs (included in base Gentoo) emerge upx ./configure make make install ## Release tests make dist make distcheck ## Optional: software MIDI support, used by SDL_mixer # Check doc/sound.txt for details emerge media-sound/timidity++ echo "media-sound/timidity-freepats **" >> /etc/portage/package.keywords emerge media-sound/timidity-freepats # GPLv>=2 + lax exception emerge media-sound/timidity-eawpatches # non-free # :) On a minimal ArchLinux system ============================= ## Bootstrap # Update packages list pacman -Sy # Source code: pacman -S git git clone git://git.sv.gnu.org/freedink cd freedink # Gnulib (cd /usr/src && git clone git://git.sv.gnu.org/gnulib) # No ArchLinux package, but there's no need for one. # Install development tools (autoconf automake gcc m4 make pkgconfig) pacman -S base-devel pacman -S help2man # to rebuild manpages pacman -S gettext # for i18n sh bootstrap ## Dependencies # I also assume you already have GCC and Make ;) pacman -S sdl # (if not already done in bootstrap step) pacman -S sdl_gfx sdl_ttf sdl_image sdl_mixer fontconfig # Optional: # - upx compresses binary # - bzip is for .tar.bz2 release tarballs (included in base Gentoo) pacman -S bzip2 upx ./configure make make install ## Release tests make dist make distcheck ## Optional: software MIDI support, used by SDL_mixer # Check doc/sound.txt for details pacman -S timidity++ pacman -S timidity-freepats # GPLv>=2 + lax exception cp /etc/timidity++/timidity-freepats.cfg /etc/timidity++/timidity.cfg yaourt -S timidity-eawpatches # non-free, in the AUR cp /etc/timidity++/timidity-eawpats.cfg /etc/timidity++/timidity.cfg # :) On a minimal FreeBSD 10.0 system =============================== ## Bootstrap # Source code: pkg install -y git git clone git://git.sv.gnu.org/freedink cd freedink/ # Gnulib (cd /usr/src && git clone git://git.sv.gnu.org/gnulib) # autoconf automake: base autotools # pkgconf: for PKG_CHECK_MODULES # help2man: to rebuild manpages # gettext autopoint: for i18n # rsync: to fetch translationproject.org pkg install -y autoconf automake pkgconf help2man gettext rsync sh bootstrap ## Dependencies # I assume you already have GCC and Make ;) pkg install -y sdl sdl_gfx sdl_ttf sdl_image sdl_mixer fontconfig # Optional: # - upx compresses binary # - bzip is for .tar.bz2 release tarballs (included in base FreeBSD) pkg install -y upx ./configure make -k # TODO: issue with spurious newlines added by msgmerge make install -k ## Release tests make dist make distcheck ## Optional: software MIDI support, used by SDL_mixer # Check doc/sound.txt for details # timidity already installed as dependencies # from SDL_mixer pkg install -y freepats # To test, see http://www.freebsd.org/doc/en/books/handbook/x-config.html # pkg install x11 # startx # :) On a minimal Woe system ======================= Check doc/cross.txt (for cross compiling from GNU/Linux + MinGW32) or doc/woe-compile.txt (for compiling from native MinGW32). freedink-109.6/README0000644000175000017500000000762013432107310011120 00000000000000This is GNU FreeDink, a portable and enhanced version of the Dink Smallwood game engine. FreeDink is free software, and you are welcome to redistribute it under certain conditions; see the GNU GPL for details. ( cf. COPYING and http://gnu.org/licenses/gpl.html ) Building -------- If you are compiling GNU FreeDink from sources, check BUILD for instructions. About Dink Smallwood -------------------- Dink Smallwood is an adventure/role-playing game, similar to classic Zelda, made by RTsoft. Besides twisted humour, it includes the actual game editor, allowing players to create hundreds of new adventures called Dink Modules or D-Mods for short. The Dink Network (http://www.dinknetwork.com/) hosts a copy of almost all of them. GNU FreeDink ------------ GNU FreeDink is a new and portable version of the game engine, which runs the original game as well as its D-Mods, with close compatibility, under multiple platforms. FreeDink can run in 2 modes: * v1.08 (default): this matches the latest release of the Dink engine, which includes some new features and some backward-incompatible changes. Use it for recent D-Mods. * v1.07 (with option '--v1.07'): this matches v1.07 of the Dink engine, essentially unmodified since 1998. Use it to play D-Mods released before 2006. Next step is extending the engine while preserving accurate support for released D-Mods. On the technical level, the internals of the engines experience a clean-up to allow for portability and later improvements. Check out FreeDink's website at http://www.freedink.org/ . Game keys --------- Keyboard controls Makes Dink walk/push Attack/Use equipped item/Select option Talk/Examine/Manipulate Use equipped magic Inventory/Equip screen Options Display map (if you have one) Toggle fullscreen mode When maintained, enable Turbo mode Keyboard controls: Inventory/Equip screen Highlight Item/Weapon or Magic Select highlighted Item/Weapon or Magic Exit inventory screen Joystick/Gamepad controls Makes Dink walk/push

Language:

Local files:


Resize canvas Lock/hide mouse pointer    
Downloading...
GNU FreeDink - Get D-Mods at The Dink Network - Original game by RTSoft - Brought to the web with emscripten - Source Code
{{{ SCRIPT }}} freedink-109.6/emscripten/extract.c0000644000175000017500000003553713420460775014255 00000000000000/** * Efficient tar+bzip2 extractor for in-game use * Copyright (C) 2004 Andrew Reading * Copyright (C) 2007, 2008, 2014, 2018 Sylvain Beucler * This file is part of GNU FreeDink * GNU FreeDink is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 3 of the * License, or (at your option) any later version. * GNU FreeDink is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see * . */ #ifdef HAVE_CONFIG_H #include #else #define _(s) s #endif #include #include #include #include #include #include #include #include #include struct TarHeader { char Name[100+1]; // 100 char Mode[8+1]; // 108 char Uid[8+1]; // 116 char Gid[8+1]; // 124 char Size[12+1]; // 136 char Mtime[12+1]; // 148 char Chksum[8+1]; // 156 char Linkflag[1+1]; // 157 char Linkname[100+1]; // 257 char Magic[8+1]; // 265 char Uname[32+1]; // 297 char Gname[32+1]; // 329 char Devmajor[8+1]; // 337 char Devminor[8+1]; // 345 char Padding[167+1]; // 512 }; #define TAR_HEADER_SIZE 512 int mkdir_rec(char* path) { int ret; mode_t mode = 00755; ret = mkdir(path, mode); if (ret == 0 || errno == EEXIST) { return 0; } else { char* dir = strdup(path); dirname(dir); ret = mkdir_rec(dir); free(dir); if (ret < 0) { return ret; } if ((ret = mkdir(path, mode)) < 0) { perror("mkdir"); return ret; } return 0; } } int DirExists(char* path) { struct stat st; return (stat(path, &st) == 0 && S_ISDIR(st.st_mode)); } void print_bzerror(BZFILE* bzin, int bzerror) { printf("%s\n", BZ2_bzerror(bzin, &bzerror)); if (bzerror == BZ_OK || bzerror == BZ_STREAM_END) { // Success } else if (bzerror == BZ_PARAM_ERROR) { printf(_("Invalid .dmod file specified.")); } else if (bzerror == BZ_SEQUENCE_ERROR) { printf(_("Critical program function error: opened for write.")); } else if (bzerror == BZ_IO_ERROR) { printf(_("Could not read .dmod file.") ); } else if (bzerror == BZ_UNEXPECTED_EOF) { printf(_("Incomplete .dmod file. Please download it again.") ); } else if (bzerror == BZ_DATA_ERROR) { printf(_("The .dmod file is corrupted. Please download it again.")); } else if (bzerror == BZ_DATA_ERROR_MAGIC) { printf(_("The file is not a valid .dmod file.")); } else if (bzerror == BZ_MEM_ERROR) { printf(_("Out of memory error.")); } else { printf(_("An unhandled error occurred.")); } printf("\n"); } /** * Read all tar headers from a flux, so it can work if reading file * with BZip2 directly (only the 'read' operation is available). */ int TarFillHeaderFromStream(BZFILE* bzin, struct TarHeader* tarHeader) { memset(tarHeader, 0, sizeof(*tarHeader)); // Read the data. Don't load the whole header to a struct, you // never know what the memory alignment will be, especially in // these 32->64bits days int bzerror; BZ2_bzRead(&bzerror, bzin, tarHeader->Name, 100); if (bzerror != BZ_OK) { print_bzerror(bzin, bzerror); return 1; } BZ2_bzRead(&bzerror, bzin, tarHeader->Mode, 8); if (bzerror != BZ_OK) { print_bzerror(bzin, bzerror); return 1; } BZ2_bzRead(&bzerror, bzin, tarHeader->Uid, 8); if (bzerror != BZ_OK) { print_bzerror(bzin, bzerror); return 1; } BZ2_bzRead(&bzerror, bzin, tarHeader->Gid, 8); if (bzerror != BZ_OK) { print_bzerror(bzin, bzerror); return 1; } BZ2_bzRead(&bzerror, bzin, tarHeader->Size, 12); if (bzerror != BZ_OK) { print_bzerror(bzin, bzerror); return 1; } BZ2_bzRead(&bzerror, bzin, tarHeader->Mtime, 12); if (bzerror != BZ_OK) { print_bzerror(bzin, bzerror); return 1; } BZ2_bzRead(&bzerror, bzin, tarHeader->Chksum, 8); if (bzerror != BZ_OK) { print_bzerror(bzin, bzerror); return 1; } BZ2_bzRead(&bzerror, bzin, tarHeader->Linkflag, 1); if (bzerror != BZ_OK) { print_bzerror(bzin, bzerror); return 1; } BZ2_bzRead(&bzerror, bzin, tarHeader->Linkname, 100); if (bzerror != BZ_OK) { print_bzerror(bzin, bzerror); return 1; } BZ2_bzRead(&bzerror, bzin, tarHeader->Magic, 8); if (bzerror != BZ_OK) { print_bzerror(bzin, bzerror); return 1; } BZ2_bzRead(&bzerror, bzin, tarHeader->Uname, 32); if (bzerror != BZ_OK) { print_bzerror(bzin, bzerror); return 1; } BZ2_bzRead(&bzerror, bzin, tarHeader->Gname, 32); if (bzerror != BZ_OK) { print_bzerror(bzin, bzerror); return 1; } BZ2_bzRead(&bzerror, bzin, tarHeader->Devmajor, 8); if (bzerror != BZ_OK) { print_bzerror(bzin, bzerror); return 1; } BZ2_bzRead(&bzerror, bzin, tarHeader->Devminor, 8); if (bzerror != BZ_OK) { print_bzerror(bzin, bzerror); return 1; } BZ2_bzRead(&bzerror, bzin, tarHeader->Padding, 167); if (bzerror != BZ_OK) { print_bzerror(bzin, bzerror); return 1; } return bzerror; } unsigned int TarComputeChecksum(struct TarHeader* tarHeader) { unsigned int sum = 0; char blankChecksum[8+1] = " "; for (int i = 0; i < 100; i++) { sum += tarHeader->Name[i]; } for (int i = 0; i < 8; i++) { sum += tarHeader->Mode[i]; } for (int i = 0; i < 8; i++) { sum += tarHeader->Uid[i]; } for (int i = 0; i < 8; i++) { sum += tarHeader->Gid[i]; } for (int i = 0; i < 12; i++) { sum += tarHeader->Size[i]; } for (int i = 0; i < 12; i++) { sum += tarHeader->Mtime[i]; } //for (int i = 0; i < 8; i++) { sum += tarHeader->Chksum[i]; } for (int i = 0; i < 8; i++) { sum += blankChecksum[i]; } for (int i = 0; i < 1; i++) { sum += tarHeader->Linkflag[i]; } for (int i = 0; i < 100; i++) { sum += tarHeader->Linkname[i]; } for (int i = 0; i < 8; i++) { sum += tarHeader->Magic[i]; } for (int i = 0; i < 32; i++) { sum += tarHeader->Uname[i]; } for (int i = 0; i < 32; i++) { sum += tarHeader->Gname[i]; } for (int i = 0; i < 8; i++) { sum += tarHeader->Devmajor[i]; } for (int i = 0; i < 8; i++) { sum += tarHeader->Devminor[i]; } for (int i = 0; i < 167; i++) { sum += tarHeader->Padding[i]; } return sum; } void GetFirstDir(const char* path, char* dmodDir) { char* firstDir = ""; char* previousDir = ""; char* checkPath = malloc(strlen(path)+strlen("dummy")+1); strcpy(checkPath, path); // tokenizer never returns empty strings + distinguish dir// and a/$ char last = path[strlen(path)-1]; if (last == '\\' || last == '/') strcat(checkPath, "dummy"); char *str, *curDir, *saveptr; for (str = checkPath; ; str = NULL) { curDir = strtok_r(str, "/\\", &saveptr); if (curDir == NULL) break; if (strcmp(curDir, ".") == 0) continue; if (strcmp(previousDir, "") != 0) { firstDir = previousDir; break; } previousDir = curDir; } strcpy(dmodDir, firstDir); free(checkPath); } int TarIsPathInsecure(char* path, char* prefix) { if (path[0] == '/' || path[0] == '\\') return 1; { char *str, *token, *saveptr; str = strdup(path); token = strtok_r(str, "/\\", &saveptr); if (strcmp(token, prefix) != 0) { free(str); return 1; } free(str); } { char *str, *token, *saveptr; for (str = path; ; str = NULL) { token = strtok_r(str, "/\\", &saveptr); if (token == NULL) break; if (strcmp(token, "..") == 0) return 1; } } return 0; } int DmodExtract(FILE* dmodFile, char* destDir, char** extractedDmodDir) { // Get the file size unsigned long dmodFileCompressedSize; if (fseek(dmodFile, 0, SEEK_END) < 0) perror("fseek"); dmodFileCompressedSize = ftell(dmodFile); if (fseek(dmodFile, 0, SEEK_SET) < 0) perror("fseek"); int bzerror = BZ_OK; BZFILE* bzin = BZ2_bzReadOpen(&bzerror, dmodFile, 0, 0, 0, 0); if (bzerror != BZ_OK) { print_bzerror(bzin, bzerror); printf(_("Error: Invalid .dmod file selected!")); printf("\n"); return -1; } struct TarHeader tarHeader; unsigned int total_read = 0; int lastPercent = 0; char dmodDir[100+1] = {}; // Keep getting chunks of the file while (1) { unsigned char* buf; int nbReadUncompressed; int ret = TarFillHeaderFromStream(bzin, &tarHeader); total_read += 512; if (ret < 0) { break; } // Define dmodDir which needs to be consistent in all the archive if (strcmp(dmodDir, "") == 0) { GetFirstDir(tarHeader.Name, dmodDir); if (strcmp(dmodDir, "") == 0 || strcmp(dmodDir, "..") == 0) { printf(_("Error: empty D-Mod directory. Stopping.\n")); return 1; } char* dmodFullPath = malloc(strlen(destDir)+1+strlen(dmodDir)+1); sprintf(dmodFullPath, "%s/%s", destDir, dmodDir); if (DirExists(dmodFullPath)) { printf(_("Error: directory '%s' already exists. Stopping.\n"), dmodDir); free(dmodFullPath); return 1; } free(dmodFullPath); printf("D-Mod dir: %s\n", dmodDir); } // Bug fix for phantom files that aren't really files... // This is due to a bug in DFArc1.5 with empty files if (strcmp(tarHeader.Name, "\xFF") == 0) { continue; } // Tar files (except for a design bug in DFArc1.5) have a // multitude of NULL characters at the end to round up to the // 10K mark. If the header is blank, we don't have any more // data. if (strcmp(tarHeader.Name, "") == 0) { break; } // TODO: ISO-8869-1 -> UTF-8? // Size unsigned long fileSize = 0; sscanf((const char*)&tarHeader.Size, "%lo", &fileSize); // Extract char last = tarHeader.Name[strlen(tarHeader.Name)-1]; if (last == '\\' || last == '/') { // directory, skip and let mkdir_rec do its job } else { unsigned int checksum = 0; unsigned int expected = TarComputeChecksum(&tarHeader); sscanf((const char*)&tarHeader.Chksum, "%o", &checksum); if (checksum != expected) { printf("Incorrect checksum, but proceeding anyway: found 0%o, expected 0%o\n", checksum, expected); } char* checkName = strdup(tarHeader.Name); if (TarIsPathInsecure(checkName, dmodDir)) { printf("Insecure path, stopping: %s\n", tarHeader.Name); free(checkName); return 1; } free(checkName); char* destFullPath = malloc(strlen(destDir)+1+strlen(tarHeader.Name)+1); sprintf(destFullPath, "%s/%s", destDir, tarHeader.Name); //printf("* Extracting to: %s\n", destFullPath); char* dir = strdup(destFullPath); dirname(dir); int ret = mkdir_rec(dir); if (ret < 0) printf("Error creating directory %s\n", dir); free(dir); if (ret < 0) { free(destFullPath); break; } { // bzip2 -9 -> 900kiB blocks - randomly using 4MiB buf, we // might get better precision with low-level BZ2 API char buf[4*1024*1024]; FILE* out = fopen(destFullPath, "wb"); if (out == NULL) { perror("fopen"); break; } unsigned long nbRemaining = fileSize; while (nbRemaining > 0) { nbReadUncompressed = (nbRemaining > sizeof(buf)) ? sizeof(buf) : nbRemaining; nbReadUncompressed = BZ2_bzRead(&bzerror, bzin, buf, nbReadUncompressed); if (bzerror != BZ_OK && bzerror != BZ_STREAM_END) { print_bzerror(bzin, bzerror); return 1; }; fwrite(buf, nbReadUncompressed, 1, out); nbRemaining -= nbReadUncompressed; { unsigned long pos = ftell(dmodFile); double percent = 100.0 * pos / dmodFileCompressedSize; if ((int)percent != lastPercent) printf("progress: %lu %lu %.02f%%\n", pos, dmodFileCompressedSize, percent); lastPercent = (int)percent; } } if (bzerror == BZ_STREAM_END) { // old .mod without end-of-archive record nor padding, no error output break; } fclose(out); } free(destFullPath); total_read += fileSize; } // Move to the beginning of the next header char padding[512]; int padding_size = (512 - (total_read % 512)) % 512; BZ2_bzRead(&bzerror, bzin, padding, padding_size); if (bzerror != BZ_OK) { print_bzerror(bzin, bzerror); return 1; } total_read += padding_size; } BZ2_bzReadClose(&bzerror, bzin); if (extractedDmodDir != NULL) { *extractedDmodDir = strdup(dmodDir); } return 0; } int emDmodExtract(char* filename, char* destdir, char** extractedDmodDir) { // printf("emDmodExtract(%s, %s)\n", filename, destdir); FILE* in = fopen(filename, "rb"); if (in == NULL) { perror("fopen"); printf("Cannot open %s\n", filename); return 1; } return DmodExtract(in, destdir, extractedDmodDir); } #ifdef TEST int main(int argc, char* argv[]) { { char buf[100+1]; assert((strcpy(buf, "../"), TarIsPathInsecure(buf, "..") == 1)); assert((strcpy(buf, "/../"), TarIsPathInsecure(buf, "") == 1)); assert((strcpy(buf, "/../"), TarIsPathInsecure(buf, "..") == 1)); assert((strcpy(buf, ".."), TarIsPathInsecure(buf, "..") == 1)); assert((strcpy(buf, "/.."), TarIsPathInsecure(buf, "") == 1)); assert((strcpy(buf, "/.."), TarIsPathInsecure(buf, "..") == 1)); assert((strcpy(buf, "path/.."), TarIsPathInsecure(buf, "path") == 1)); assert((strcpy(buf, "path/subpath/.."), TarIsPathInsecure(buf, "path") == 1)); assert((strcpy(buf, "path/../subpath"), TarIsPathInsecure(buf, "path") == 1)); assert((strcpy(buf, "../path/subpath"), TarIsPathInsecure(buf, "..") == 1)); assert((strcpy(buf, "../path/subpath"), TarIsPathInsecure(buf, "path") == 1)); assert((strcpy(buf, "/path/subpath"), TarIsPathInsecure(buf, "") == 1)); assert((strcpy(buf, "/path/subpath"), TarIsPathInsecure(buf, "path") == 1)); assert((strcpy(buf, "\\path/subpath"), TarIsPathInsecure(buf, "") == 1)); assert((strcpy(buf, "\\path/subpath"), TarIsPathInsecure(buf, "path") == 1)); assert((strcpy(buf, "path\\..\\subpath"), TarIsPathInsecure(buf, "path") == 1)); assert((strcpy(buf, "path"), TarIsPathInsecure(buf, "path") == 0)); assert((strcpy(buf, "path"), TarIsPathInsecure(buf, "path") == 0)); assert((strcpy(buf, "path/"), TarIsPathInsecure(buf, "path") == 0)); assert((strcpy(buf, "path\\"), TarIsPathInsecure(buf, "path") == 0)); assert((strcpy(buf, "path/subpath"), TarIsPathInsecure(buf, "path") == 0)); assert((strcpy(buf, "path\\subpath"), TarIsPathInsecure(buf, "path") == 0)); assert((strcpy(buf, "path2\\subpath"), TarIsPathInsecure(buf, "path") == 1)); assert((strcpy(buf, "dink.exe"), TarIsPathInsecure(buf, "path") == 1)); assert((strcpy(buf, "dink.exe"), TarIsPathInsecure(buf, "path") == 1)); } return emDmodExtract(argv[1], "/tmp/testdmod", NULL); } #endif freedink-109.6/emscripten/post.js0000644000175000017500000000000013420460775013733 00000000000000freedink-109.6/emscripten/importexport.c0000644000175000017500000001204613420460775015345 00000000000000/** * Import/export ~/.dink/ as .zip * Copyright (C) 2018 Sylvain Beucler * This file is part of GNU FreeDink * GNU FreeDink is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 3 of the * License, or (at your option) any later version. * GNU FreeDink is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see * . */ #include #include #include #include #include #include #include #include #include extern int mkdir_rec(char* path); int IsDir(char* path) { struct stat st; return (stat(path, &st) == 0 && S_ISDIR(st.st_mode)); } int AddFileToZip(zip_t* archive, char* path, char* prefix) { zip_source_t *s; s = zip_source_file(archive, path, 0, -1); if (s == NULL) { fprintf(stderr, "error opening %s\n", path); return 0; } char* zippath = path + strlen(prefix); if (zip_file_add(archive, zippath, s, ZIP_FL_ENC_UTF_8) < 0) { zip_source_free(s); fprintf(stderr, "error adding %s: %s\n", path, zip_strerror(archive)); return 0; } return 1; } int AddPathToZip(zip_t* archive, char* path, char* prefix) { //printf("processing %s\n", path); struct stat st; if (IsDir(path)) { DIR* dir = opendir(path); if (dir == NULL) { perror("opendir"); return 0; } struct dirent *ent; while ((ent = readdir(dir)) != NULL) { //printf("dir: %s\n", ent->d_name); if (strcmp(ent->d_name, ".") == 0) continue; if (strcmp(ent->d_name, "..") == 0) continue; char* subpath = malloc(strlen(path) + 1 + strlen(ent->d_name) + 1); sprintf(subpath, "%s/%s", path, ent->d_name); AddPathToZip(archive, subpath, prefix); free(subpath); } closedir(dir); } else { AddFileToZip(archive, path, prefix); } return 1; } int emSavegamesExport(void) { int errorp; zip_t* archive = zip_open("savegames.zip", ZIP_CREATE|ZIP_TRUNCATE|ZIP_CHECKCONS, &errorp); if (archive == NULL) { zip_error_t error; zip_error_init_with_code(&error, errorp); fprintf(stderr, "error creating savegames.zip: %s\n", zip_error_strerror(&error)); zip_error_fini(&error); return 0; } char* path = malloc(strlen(getenv("HOME"))+1+strlen(".dink")+1); sprintf(path, "%s/%s", getenv("HOME"), ".dink"); char* prefix = malloc(strlen(getenv("HOME"))+1+strlen(".dink")+1+1); sprintf(prefix, "%s/%s/", getenv("HOME"), ".dink"); AddPathToZip(archive, path, prefix); free(path); if (zip_get_num_entries(archive, 0) == 0) { printf("No savegames found!\n"); return 0; } else if (zip_close(archive) < 0) { fprintf(stderr, "cannot write savegames.zip: %s\n", zip_strerror(archive)); return 0; } chmod("savegames.zip", 00666); return 1; } void emSavegamesImport(void) { int errorp; zip_t* archive = zip_open("/savegames.zip", ZIP_RDONLY, &errorp); if (archive == NULL) { zip_error_t error; zip_error_init_with_code(&error, errorp); fprintf(stderr, "error opening savegames.zip: %s\n", zip_error_strerror(&error)); zip_error_fini(&error); return; } char* prefix = malloc(strlen(getenv("HOME"))+1+strlen(".dink")+1+1); sprintf(prefix, "%s/%s/", getenv("HOME"), ".dink"); for (int i = 0; i < zip_get_num_entries(archive, 0); i++) { zip_stat_t sb; zip_stat_index(archive, i, 0, &sb); if (!(sb.valid & ZIP_STAT_NAME) || !(sb.valid & ZIP_STAT_SIZE)) { continue; } if (sb.name[strlen(sb.name)-1] == '/') { // will recursively create directories later continue; } char* destFullPath = malloc(strlen(prefix)+strlen(sb.name)+1); sprintf(destFullPath, "%s%s", prefix, sb.name); char* dir = strdup(destFullPath); dirname(dir); int ret = mkdir_rec(dir); if (ret < 0) printf("Error creating directory %s\n", dir); free(dir); if (ret < 0) continue; zip_file_t* file; if ((file = zip_fopen_index(archive, i, 0)) == NULL) { fprintf(stderr, "error opening file %d: %s\n", i, zip_strerror(archive)); continue; } FILE* out; if ((out = fopen(destFullPath, "wb")) == NULL) { perror("fopen"); continue; } unsigned char buf[4096]; // size from emscripten implementation zip_uint64_t total = 0; while (total < sb.size) { zip_int64_t nb_read; if ((nb_read = zip_fread(file, buf, sizeof(buf))) < 0) { fprintf(stderr, "error reading %s: %s\n", sb.name, zip_file_strerror(file)); continue; } fwrite(buf, nb_read, 1, out); total += nb_read; } fclose(out); zip_fclose(file); free(destFullPath); } } #ifdef TEST int main(void) { return !emSavegamesExport(); } #endif freedink-109.6/emscripten/source.html0000644000175000017500000000565713430054031014606 00000000000000 GNU FreeDink - source code

Attributions and source code copies required by GNU FreeDink and its dependencies:

JavaScript Web Labels:

index.html GNU-GPL-3.0-or-later index.html
index.js GNU-GPL-3.0-or-later freedink-109.0.tar.gz
index.wasm GNU-GPL-3.0-or-later freedink-109.0.tar.gz
index.html GNU-GPL-3.0-or-later asmjs/index.html
asmjs/index.js GNU-GPL-3.0-or-later freedink-109.0.tar.gz
freedink-109.6/README.txt0000644000175000017500000001002613432116467011745 00000000000000This is GNU FreeDink, a portable and enhanced version of the Dink Smallwood game engine. FreeDink is free software, and you are welcome to redistribute it under certain conditions; see the GNU GPL for details. ( cf. COPYING and http://gnu.org/licenses/gpl.html ) Building -------- If you are compiling GNU FreeDink from sources, check BUILD for instructions. About Dink Smallwood -------------------- Dink Smallwood is an adventure/role-playing game, similar to classic Zelda, made by RTsoft. Besides twisted humour, it includes the actual game editor, allowing players to create hundreds of new adventures called Dink Modules or D-Mods for short. The Dink Network (http://www.dinknetwork.com/) hosts a copy of almost all of them. GNU FreeDink ------------ GNU FreeDink is a new and portable version of the game engine, which runs the original game as well as its D-Mods, with close compatibility, under multiple platforms. FreeDink can run in 2 modes: * v1.08 (default): this matches the latest release of the Dink engine, which includes some new features and some backward-incompatible changes. Use it for recent D-Mods. * v1.07 (with option '--v1.07'): this matches v1.07 of the Dink engine, essentially unmodified since 1998. Use it to play D-Mods released before 2006. Next step is extending the engine while preserving accurate support for released D-Mods. On the technical level, the internals of the engines experience a clean-up to allow for portability and later improvements. Check out FreeDink's website at http://www.freedink.org/ . Game keys --------- Keyboard controls Makes Dink walk/push Attack/Use equipped item/Select option Talk/Examine/Manipulate Use equipped magic Inventory/Equip screen Options Display map (if you have one) Toggle fullscreen mode When maintained, enable Turbo mode Keyboard controls: Inventory/Equip screen Highlight Item/Weapon or Magic Select highlighted Item/Weapon or Magic Exit inventory screen Joystick/Gamepad controls Makes Dink walk/push