From f5086e0845b6421e782ccebb9fa1f6382cb01987 Mon Sep 17 00:00:00 2001 From: Vladimir Serbinenko Date: Mon, 13 Mar 2023 20:38:09 +0100 Subject: [PATCH] SCUMM: Add a tool for extracting nd4 archive as used by floppy version of indy4 --- Makefile.common | 6 ++ engines/scumm/extract_lfg.cpp | 114 ++++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 engines/scumm/extract_lfg.cpp diff --git a/Makefile.common b/Makefile.common index af5e53d7..1ec1a5ac 100644 --- a/Makefile.common +++ b/Makefile.common @@ -41,6 +41,7 @@ PROGRAMS = \ extract_hadesch_img \ extract_lokalizator \ extract_mps \ + extract_lfg \ grim_animb2txt \ grim_bm2bmp \ grim_cosb2cos \ @@ -160,6 +161,11 @@ extract_mps_OBJS := \ common/dcl.o \ $(UTILS) +extract_lfg_OBJS := \ + engines/scumm/extract_lfg.o \ + common/dcl.o \ + $(UTILS) + deprince_OBJS := \ engines/prince/deprince.o \ engines/prince/flags.o \ diff --git a/engines/scumm/extract_lfg.cpp b/engines/scumm/extract_lfg.cpp new file mode 100644 index 00000000..8bd86196 --- /dev/null +++ b/engines/scumm/extract_lfg.cpp @@ -0,0 +1,114 @@ +/* ScummVM Tools + * + * ScummVM Tools is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program 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. + * + * This program 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 "common/endian.h" +#include "common/memstream.h" +#include "common/file.h" +#include "common/str.h" +#include "common/util.h" +#include "common/dcl.h" +#include +#include +#include +#include + +int main (int argc, char **argv) { + unsigned char *buf = nullptr; + size_t inSize = 0; + + if (argc < 3) { + fprintf (stderr, "USAGE: %s OUTDIR VOLUMES\n", argv[0]); + return -1; + } + + for (int i = 2; i < argc; i++) { + FILE *fin = fopen (argv[i], "rb"); + byte head[8]; + if (fin == NULL) { + fprintf (stderr, "Unable to open %s: %s\n", argv[i], strerror(errno)); + free (buf); + return -2; + } + fread (head, 1, 8, fin); + if (READ_BE_UINT32(head) != MKTAG('L', 'F', 'G', '!')) { + fprintf (stderr, "%s doesn't contain magic\n", argv[i]); + free (buf); + return -2; + } + uint32 volumeSize = READ_LE_UINT32(head + 4); + uint32 oldInSize = inSize; + inSize += volumeSize; + + buf = (byte *) realloc (buf, inSize); + fread (buf + oldInSize, 1, volumeSize, fin); + fclose (fin); + } + + printf("Archive name: %s\n", buf); + printf("Value A=0x%x\n", buf[13]); + printf("Value B=0x%x\n", READ_LE_UINT16(buf+14)); + printf("Total number of bytes=0x%x\n", READ_LE_UINT32(buf+16)); + + for (byte *ptr = buf + 0x14; ptr < buf + inSize;) { + uint32 magic = READ_BE_UINT32(ptr); + if (magic != MKTAG('F', 'I', 'L', 'E')) { + printf("Wrong magic: %x @ %x\n", magic, (int)(ptr - buf)); + free (buf); + return 0; + } + uint32 blocklen = READ_LE_UINT32(ptr + 4); + byte *blockend = ptr + 8 + blocklen; + ptr += 8; + Common::String name((char *)ptr, 13); + ptr += 13; + Common::File fout(Common::String::format("%s/%s", argv[1], name.c_str()), "wb"); + uint32 uncompressedSize = READ_LE_UINT32(ptr + 1); + printf("name: %s\n", name.c_str()); + printf("value C=0x%x\n", ptr[0]); + // ptr[0] is always 0x17 or 0x19 so far + // ptr + 5 is always 02 00 01 00 00 00 so far + printf("value D:\n"); + hexdump(ptr + 5, 6); + // Most likely it contains compression somewhere + ptr += 11; + + uint32 compressedSize = blockend - ptr; + byte *uncompressedBuf = nullptr; + + // DCL. TODO: Support uncompressed if needed + Common::MemoryReadStream compressedReadStream(ptr, compressedSize); + uncompressedBuf = new byte[uncompressedSize]; + if (!Common::decompressDCL(&compressedReadStream, uncompressedBuf, compressedSize, uncompressedSize)) { + fprintf (stderr, "Unable to decompress %s\n", name.c_str()); + delete[] uncompressedBuf; + continue; + } + + fout.write(uncompressedBuf, uncompressedSize); + ptr = blockend; + + delete[] uncompressedBuf; + } + + free (buf); + + return 0; +}