diff --git a/devtools/create_supernova/create_supernova.cpp b/devtools/create_supernova/create_supernova.cpp new file mode 100644 index 00000000000..0d4ebe2fe7d --- /dev/null +++ b/devtools/create_supernova/create_supernova.cpp @@ -0,0 +1,193 @@ +#include "create_supernova.h" +#include "gametext.h" +#include "file.h" + +// HACK to allow building with the SDL backend on MinGW +// see bug #1800764 "TOOLS: MinGW tools building broken" +#ifdef main +#undef main +#endif // main + +// List of languages to look for. To add new languages you only need to change the array below +// and add the supporting files: +// - 640x480 bitmap picture for the newpaper named 'img1-##.pbm' and 'img2-##.pbm' +// in pbm binary format (you can use gimp to generate those) +// - strings in a po file named 'strings-##.po' that uses CP850 encoding + +const char *lang[] = { + "en", + NULL +}; + +void writeImage(File& outputFile, const char *name, const char* language) { + File imgFile; + char fileName[16]; + sprintf(fileName, "%s-%s.pbm", name, language); + if (!imgFile.open(fileName, kFileReadMode)) { + printf("Cannot find image '%s' for language '%s'. This image will be skipped.\n", name, language); + return; + } + + char str[256]; + + // Read header (and check we have a binary PBM file) + imgFile.readString(str, 256); + if (strcmp(str, "P4") != 0) { + imgFile.close(); + printf("File '%s' doesn't seem to be a binary pbm file! This image will be skipped.\n", fileName); + return; + } + + // Skip comments and then read and check size + do { + imgFile.readString(str, 256); + } while (str[0] == '#'); + int w = 0, h = 0; + if (sscanf(str, "%d %d", &w, &h) != 2 || w != 640 || h != 480) { + imgFile.close(); + printf("Binary pbm file '%s' doesn't have the expected size (expected: 640x480, read: %dx%d). This image will be skipped.\n", fileName, w, h); + return; + } + + // Write block header in output file (4 bytes). + // We convert the image name to upper case. + for (int i = 0 ; i < 4 ; ++i) { + if (name[i] >= 97 && name[i] <= 122) + outputFile.writeByte(name[i] - 32); + else + outputFile.writeByte(name[i]); + } + // And write the language code on 4 bytes as well (padded with 0 if needed). + int languageLength = strlen(language); + for (int i = 0 ; i < 4 ; ++i) { + if (i < languageLength) + outputFile.writeByte(language[i]); + else + outputFile.writeByte(0); + } + + // Write block size (640*480 / 8) + outputFile.writeLong(38400); + + // Write all the bytes. We should have 38400 bytes (640 * 480 / 8) + // However we need to invert the bits has the engine expects 1 for the background and 0 for the text (black) + // but pbm uses 0 for white and 1 for black. + for (int i = 0 ; i < 38400 ; ++i) { + byte b = imgFile.readByte(); + outputFile.writeByte(~b); + } + + imgFile.close(); +} + +void writeGermanStrings(File& outputFile) { + // Write header and language + outputFile.write("TEXT", 4); + outputFile.write("de\0\0", 4); + + // Reserve the size for the block size, but we will write it at the end once we know what it is. + uint32 blockSizePos = outputFile.pos(); + uint32 blockSize = 0; + outputFile.writeLong(blockSize); + + // Write all the strings + const char **s = &gameText[0]; + while (*s) { + outputFile.writeString(*s); + blockSize += strlen(*s) + 1; + ++s; + } + + // Now write the block size and then go back to the end of the file. + outputFile.seek(blockSizePos, SEEK_SET); + outputFile.writeLong(blockSize); + outputFile.seek(0, SEEK_END); +} + +void writeStrings(File& outputFile, const char* language) { + File poFile; + char fileName[16]; + sprintf(fileName, "strings-%s.po", language); + if (!poFile.open(fileName, kFileReadMode)) { + printf("Cannot find strings file for language '%s'.\n", language); + return; + } + + // Write block header + outputFile.write("TEXT", 4); + + // And write the language code on 4 bytes as well (padded with 0 if needed). + int languageLength = strlen(language); + for (int i = 0 ; i < 4 ; ++i) { + if (i < languageLength) + outputFile.writeByte(language[i]); + else + outputFile.writeByte(0); + } + + // Reserve the size for the block size, but we will write it at the end once we know what it is. + uint32 blockSizePos = outputFile.pos(); + uint32 blockSize = 0; + outputFile.writeLong(blockSize); + + + + // TODO: read all the strings + // build german - translated map + // Then iterate on gameText and for each (german) string look for the corresponding translated string + // and write it (or write "" if not found). + // Doing so also count the number of byte written. + // Then finally go back to block size pos and write the block size. + // And go back to end of file. + + + + poFile.close(); + + // Now write the block size and then go back to the end of the file. + outputFile.seek(blockSizePos, SEEK_SET); + outputFile.writeLong(blockSize); + outputFile.seek(0, SEEK_END); +} + + +/** + * Main method + */ +int main(int argc, char *argv[]) { + File outputFile; + if (!outputFile.open("supernova.dat", kFileWriteMode)) { + printf("Cannot create file 'supernova.dat' in current directory.\n"); + exit(0); + } + + // The generated file is of the form: + // 3 bytes: 'MSN' + // 1 byte: version + // -- data blocks + // 4 bytes: header 'IMG1' and 'IMG2' for newspaper images (for file 1 and file 2 respectively), + // 'TEXT' for strings + // 4 bytes: language code ('en\0', 'de\0'- see common/language.cpp) + // 4 bytes: block size n (uint32) + // n bytes: data + // --- + + // Header + outputFile.write("MSN", 3); + outputFile.writeByte(VERSION); + + // German strings + writeGermanStrings(outputFile); + + // Other languages + const char **l = &lang[0]; + while(*l) { + writeImage(outputFile, "img1", *l); + writeImage(outputFile, "img2", *l); + writeStrings(outputFile, *l); + ++l; + } + + outputFile.close(); + return 0; +} diff --git a/devtools/create_supernova/create_supernova.h b/devtools/create_supernova/create_supernova.h new file mode 100644 index 00000000000..7447a7ece68 --- /dev/null +++ b/devtools/create_supernova/create_supernova.h @@ -0,0 +1,33 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * This is a utility for generating a data file for the supernova engine. + * It contains strings extracted from the original executable as well + * as translations and is required for the engine to work properly. + */ + +#ifndef CREATE_SUPERNOVA_H +#define CREATE_SUPERNOVA_H + +#define VERSION 1 + + + +#endif // CREATE_SUPERNOVA_H diff --git a/devtools/create_supernova/file.cpp b/devtools/create_supernova/file.cpp new file mode 100644 index 00000000000..5fb842aff69 --- /dev/null +++ b/devtools/create_supernova/file.cpp @@ -0,0 +1,72 @@ +#include "file.h" + +bool File::open(const char *filename, AccessMode mode) { + f = fopen(filename, (mode == kFileReadMode) ? "rb" : "wb"); + return (f != NULL); +} + +void File::close() { + fclose(f); + f = NULL; +} + +int File::seek(int32 offset, int whence) { + return fseek(f, offset, whence); +} + +long File::read(void *buffer, int len) { + return fread(buffer, 1, len, f); +} +void File::write(const void *buffer, int len) { + fwrite(buffer, 1, len, f); +} + +byte File::readByte() { + byte v; + read(&v, sizeof(byte)); + return v; +} + +uint16 File::readWord() { + uint16 v; + read(&v, sizeof(uint16)); + return FROM_LE_16(v); +} + +uint32 File::readLong() { + uint32 v; + read(&v, sizeof(uint32)); + return FROM_LE_32(v); +} + +void File::readString(char* string, int bufferLength) { + int i = 0; + while (i < bufferLength - 1 && fread(string + i, 1, 1, f) == 1) { + if (string[i] == '\n' || string[i] == 0) + break; + ++ i; + } + string[i] = 0; +} + +void File::writeByte(byte v) { + write(&v, sizeof(byte)); +} + +void File::writeWord(uint16 v) { + uint16 vTemp = TO_LE_16(v); + write(&vTemp, sizeof(uint16)); +} + +void File::writeLong(uint32 v) { + uint32 vTemp = TO_LE_32(v); + write(&vTemp, sizeof(uint32)); +} + +void File::writeString(const char *s) { + write(s, strlen(s) + 1); +} + +uint32 File::pos() { + return ftell(f); +} diff --git a/devtools/create_supernova/file.h b/devtools/create_supernova/file.h new file mode 100644 index 00000000000..dd33e410f9a --- /dev/null +++ b/devtools/create_supernova/file.h @@ -0,0 +1,59 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * This is a utility for generating a data file for the supernova engine. + * It contains strings extracted from the original executable as well + * as translations and is required for the engine to work properly. + */ + +#ifndef FILE_H +#define FILE_H + +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL +#include "common/endian.h" + +enum AccessMode { + kFileReadMode = 1, + kFileWriteMode = 2 +}; + +class File { +private: + FILE *f; +public: + bool open(const char *filename, AccessMode mode = kFileReadMode); + void close(); + int seek(int32 offset, int whence = SEEK_SET); + uint32 pos(); + long read(void *buffer, int len); + void write(const void *buffer, int len); + + byte readByte(); + uint16 readWord(); + uint32 readLong(); + void readString(char*, int bufferLength); + void writeByte(byte v); + void writeWord(uint16 v); + void writeLong(uint32 v); + void writeString(const char *s); +}; + +#endif // FILE_H diff --git a/devtools/create_supernova/gametext.h b/devtools/create_supernova/gametext.h new file mode 100644 index 00000000000..a05526088e4 --- /dev/null +++ b/devtools/create_supernova/gametext.h @@ -0,0 +1,271 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * This is a utility for generating a data file for the supernova engine. + * It contains strings extracted from the original executable as well + * as translations and is required for the engine to work properly. + */ + +#ifndef GAMETEXT_H +#define GAMETEXT_H + +#include + +// This file contains the strings in German and is encoded using CP850 encoding. +// Other language should be provided as po files also using the CP850 encoding. + +// TODO: add the strings from the engine here, add an Id string in comment. +// And in the engine add a StringId enum with all the Ids = index in this array. + +const char *gameText[] = { + // 0 + "", // + "", // + "", // + "", // + "", // + // 5 + "", // + "", // + "", // + "", // + "", // + // 10 + "", // + "", // + "", // + "", // + "", // + // 15 + "", // + "", // + "", // + "", // + "", // + // 20 + "", // + "", // + "", // + "", // + "", // + // 25 + "", // + "", // + "", // + "", // + "", // + // 30 + "", // + "", // + "", // + "", // + "", // + // 35 + "", // + "", // + "", // + "", // + "", // + // 40 + "", // + "", // + "", // + "", // + "", // + // 45 + "", // + "", // + "", // + "", // + "", // + // 50 + "", // + "", // + "", // + "", // + "", // + // 55 + "", // + "", // + "", // + "", // + "", // + // 60 + "", // + "", // + "", // + "", // + "", // + // 65 + "", // + "", // + "", // + "", // + "", // + // 70 + "", // + "", // + "", // + "", // + "", // + // 75 + "", // + "", // + "", // + "", // + "", // + // 80 + "", // + "", // + "", // + "", // + "", // + // 85 + "", // + "", // + "", // + "", // + "", // + // 90 + "", // + "", // + "", // + "", // + "", // + // 95 + "", // + "", // + "", // + "", // + "", // + // 100 + "", // + "", // + "", // + "", // + "", // + // 105 + "", // + "", // + "", // + "", // + "", // + // 110 + "", // + "", // + "", // + "", // + "", // + // 115 + "", // + "", // + "", // + "", // + "", // + // 120 + "", // + "", // + "", // + "", // + "", // + // 125 + "", // + "", // + "", // + "", // + "", // + // 130 + "", // + "", // + "", // + "", // + "", // + // 135 + "", // + "", // + "", // + "", // + "", // + // 140 + "", // + "", // + "", // + "", // + "", // + // 145 + "", // + "", // + "", // + "", // + "", // + // 150 + "", // + "", // + "", // + "", // + "", // + // 155 + "", // + "", // + "", // + "", // + "", // + // 160 + "", // + "", // + "", // + "", // + "", // + // 165 + "", // + "", // + "", // + "", // + "", // + // 170 + "", // + "", // + "", // + "", // + "", // + // 175 + "", // + "", // + "", // + "", // + "", // + // 180 + "", // + "", // + "", // + "", // + "", // + // 185 + "", // + "", // + "", // + "", // + "", // + NULL +}; + + + +#endif // GAMETEXT_H diff --git a/devtools/create_supernova/module.mk b/devtools/create_supernova/module.mk new file mode 100644 index 00000000000..9591233168c --- /dev/null +++ b/devtools/create_supernova/module.mk @@ -0,0 +1,11 @@ +MODULE := devtools/create_supernova + +MODULE_OBJS := \ + file.o \ + create_supernova.o + +# Set the name of the executable +TOOL_EXECUTABLE := create_supernova + +# Include common rules +include $(srcdir)/rules.mk