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;
+}