int AgiEngine::loadWords(const char *fname) { Common::File fp; uint32 flen; uint8 *mem = NULL; words = NULL; if (!fp.open(fname)) { warning("loadWords: can't open %s", fname); return errOK; // err_BadFileOpen } debug(0, "Loading dictionary: %s", fname); fp.seek(0, SEEK_END); flen = fp.pos(); wordsFlen = flen; fp.seek(0, SEEK_SET); if ((mem = (uint8 *)calloc(1, flen + 32)) == NULL) { fp.close(); return errNotEnoughMemory; } fp.read(mem, flen); fp.close(); words = mem; return errOK; }
/** * Loads the contents of the mort.dat data file */ Common::ErrorCode MortevielleEngine::loadMortDat() { Common::File f; // Open the mort.dat file if (!f.open(MORT_DAT)) { Common::String msg = Common::String::format(_("Unable to locate the '%s' engine data file."), MORT_DAT); GUIErrorMessage(msg); return Common::kReadingFailed; } // Validate the data file header char fileId[4]; f.read(fileId, 4); if (strncmp(fileId, "MORT", 4) != 0) { Common::String msg = Common::String::format(_("The '%s' engine data file is corrupt."), MORT_DAT); GUIErrorMessage(msg); return Common::kReadingFailed; } // Check the version int majVer = f.readByte(); int minVer = f.readByte(); if (majVer < MORT_DAT_REQUIRED_VERSION) { Common::String msg = Common::String::format( _("Incorrect version of the '%s' engine data file found. Expected %d.%d but got %d.%d."), MORT_DAT, MORT_DAT_REQUIRED_VERSION, 0, majVer, minVer); GUIErrorMessage(msg); return Common::kReadingFailed; } // Loop to load resources from the data file while (f.pos() < f.size()) { // Get the Id and size of the next resource char dataType[4]; int dataSize; f.read(dataType, 4); dataSize = f.readUint16LE(); if (!strncmp(dataType, "FONT", 4)) { // Font resource _screenSurface->readFontData(f, dataSize); } else if (!strncmp(dataType, "SSTR", 4)) { readStaticStrings(f, dataSize, kStaticStrings); } else if ((!strncmp(dataType, "GSTR", 4)) && (!_txxFileFl)) { readStaticStrings(f, dataSize, kGameStrings); } else if (!strncmp(dataType, "VERB", 4)) { _menu->readVerbNums(f, dataSize); } else { // Unknown section f.skip(dataSize); } } // Close the file f.close(); assert(_engineStrings.size() > 0); return Common::kNoError; }
/*! \brief Write the body of the STK archive * \param stk STK/ITK archive file * \param chunks Chunk list * * This function writes the body of the STK archive by storing or compressing * (or skipping duplicate files) the files. It also updates the chunk information * with the size of the chunk in the archive, the compression method (if modified), * ... */ void CompressGob::writeBody(Common::Filename *inpath, Common::File &stk, Chunk *chunks) { Chunk *curChunk = chunks; Common::File src; while (curChunk) { inpath->setFullName(curChunk->name); src.open(*inpath, "rb"); if (curChunk->packed == 2) print("Identical file %12s\t(compressed size %d bytes)", curChunk->name, curChunk->replChunk->size); curChunk->offset = stk.pos(); if (curChunk->packed == 1) { curChunk->size = writeBodyPackFile(stk, src); if (curChunk->size >= curChunk->realSize) { // If compressed size >= realsize, compression is useless // => Store instead curChunk->packed = 0; stk.seek(curChunk->offset, SEEK_SET); src.rewind(); } else print("Compressing %12s\t%d -> %d bytes", curChunk->name, curChunk->realSize, curChunk->size); } if (curChunk->packed == 0) { curChunk->size = writeBodyStoreFile(stk, src); print("Storing %12s\t%d bytes", curChunk->name, curChunk->size); } curChunk = curChunk->next; } }
/** * Opens a file and loads a sound effect. * * @param fileName Sfx filename * * @returns True is everything is OK, False otherwise */ bool FPSfx::loadFile(const char *fileName) { if (!_soundSupported) return true; SoundCodecs codec = FPCODEC_UNKNOWN; Common::File file; if (file.open(fileName)) codec = FPCODEC_ADPCM; else if (file.open(setExtension(fileName, ".MP3"))) codec = FPCODEC_MP3; else if (file.open(setExtension(fileName, ".OGG"))) codec = FPCODEC_OGG; else if (file.open(setExtension(fileName, ".FLA"))) codec = FPCODEC_FLAC; else { warning("FPSfx::LoadFile(): Cannot open sfx file!"); return false; } Common::SeekableReadStream *buffer; switch (codec) { case FPCODEC_ADPCM: { if (file.readUint32BE() != MKTAG('A', 'D', 'P', 0x10)) { warning("FPSfx::LoadFile(): Invalid ADP header!"); return false; } uint32 rate = file.readUint32LE(); uint32 channels = file.readUint32LE(); buffer = file.readStream(file.size() - file.pos()); _rewindableStream = Audio::makeADPCMStream(buffer, DisposeAfterUse::YES, 0, Audio::kADPCMDVI, rate, channels); } break; case FPCODEC_MP3: #ifdef USE_MAD buffer = file.readStream(file.size()); _rewindableStream = Audio::makeMP3Stream(buffer, DisposeAfterUse::YES); #endif break; case FPCODEC_OGG: #ifdef USE_VORBIS buffer = file.readStream(file.size()); _rewindableStream = Audio::makeVorbisStream(buffer, DisposeAfterUse::YES); #endif break; case FPCODEC_FLAC: buffer = file.readStream(file.size()); #ifdef USE_FLAC _rewindableStream = Audio::makeFLACStream(buffer, DisposeAfterUse::YES); #endif break; default: return false; } _fileLoaded = true; return true; }
int AgiEngine::loadWords_v1(Common::File &f) { char str[64]; int k; debug(0, "Loading dictionary"); // Loop through alphabet, as words in the dictionary file are sorted by // first character f.seek(f.pos() + 26 * 2, SEEK_SET); do { // Read next word for (k = 0; k < (int)sizeof(str) - 1; k++) { str[k] = f.readByte(); if (str[k] == 0 || (uint8)str[k] == 0xFF) break; } // And store it in our internal dictionary if (k > 0) { AgiWord *w = new AgiWord; w->word = myStrndup(str, k + 1); w->id = f.readUint16LE(); _game.words[str[0] - 'a'].push_back(w); debug(3, "'%s' (%d)", w->word, w->id); } } while((uint8)str[0] != 0xFF); return errOK; }
int AgiEngine::loadObjects(const char *fname) { Common::File fp; uint32 flen; uint8 *mem; _objects = NULL; _game.numObjects = 0; debugC(5, kDebugLevelResources, "(Loading objects '%s')", fname); if (!fp.open(fname)) return errBadFileOpen; fp.seek(0, SEEK_END); flen = fp.pos(); fp.seek(0, SEEK_SET); if ((mem = (uint8 *)calloc(1, flen + 32)) == NULL) { fp.close(); return errNotEnoughMemory; } fp.read(mem, flen); fp.close(); decodeObjects(mem, flen); free(mem); return errOK; }
/** * Loads the contents of the mort.dat data file */ Common::ErrorCode MortevielleEngine::loadMortDat() { Common::File f; // Open the mort.dat file if (!f.open(MORT_DAT)) { GUIErrorMessage("Could not locate 'mort.dat'."); return Common::kReadingFailed; } // Validate the data file header char fileId[4]; f.read(fileId, 4); if (strncmp(fileId, "MORT", 4) != 0) { GUIErrorMessage("The located mort.dat data file is invalid"); return Common::kReadingFailed; } // Check the version if (f.readByte() < MORT_DAT_REQUIRED_VERSION) { GUIErrorMessage("The located mort.dat data file is too old, please download an updated version on scummvm.org"); return Common::kReadingFailed; } f.readByte(); // Minor version // Loop to load resources from the data file while (f.pos() < f.size()) { // Get the Id and size of the next resource char dataType[4]; int dataSize; f.read(dataType, 4); dataSize = f.readUint16LE(); if (!strncmp(dataType, "FONT", 4)) { // Font resource _screenSurface.readFontData(f, dataSize); } else if (!strncmp(dataType, "SSTR", 4)) { readStaticStrings(f, dataSize, kStaticStrings); } else if ((!strncmp(dataType, "GSTR", 4)) && (!_txxFileFl)) { readStaticStrings(f, dataSize, kGameStrings); } else if (!strncmp(dataType, "VERB", 4)) { _menu.readVerbNums(f, dataSize); } else { // Unknown section f.skip(dataSize); } } // Close the file f.close(); assert(_engineStrings.size() > 0); return Common::kNoError; }
void ExtractCine::unpackFile(Common::File &file) { char fileName[15]; unsigned int entryCount = file.readUint16BE(); // How many entries? unsigned int entrySize = file.readUint16BE(); // How many bytes per entry? assert(entrySize == 0x1e); while (entryCount--) { file.read_throwsOnError(fileName, 14); fileName[14] = '\0'; Common::Filename outPath(_outputPath); outPath.setFullName(fileName); uint32 offset = file.readUint32BE(); unsigned int packedSize = file.readUint32BE(); unsigned int unpackedSize = file.readUint32BE(); // Skip one file.readUint32BE(); unsigned int savedPos = file.pos(); print("unpacking '%s' ... ", outPath.getFullName().c_str()); Common::File fpOut(outPath, "wb"); file.seek(offset, SEEK_SET); assert(unpackedSize >= packedSize); uint8 *data = (uint8 *)calloc(unpackedSize, 1); uint8 *packedData = (uint8 *)calloc(packedSize, 1); assert(data); assert(packedData); file.read_throwsOnError(packedData, packedSize); bool status = true; if (packedSize != unpackedSize) { CineUnpacker cineUnpacker; status = cineUnpacker.unpack(packedData, packedSize, data, unpackedSize); } else { memcpy(data, packedData, packedSize); } free(packedData); fpOut.write(data, unpackedSize); free(data); if (!status) { print("CRC ERROR"); } else { print("ok"); } print(", packedSize %u unpackedSize %u", packedSize, unpackedSize); file.seek(savedPos, SEEK_SET); } }
void writeScriptData(const char *sourceFilename, Common::File &target, RoomScripts *scripts, uint scriptCount) { Common::File source; if (!source.open(sourceFilename)) { error("Unable to open '%s'", sourceFilename); } for (uint i = 0; i < scriptCount; i++) { source.seek(scripts[i].sourceOffset); scripts[i].targetOffset = target.pos(); byte *buffer = new byte[scripts[i].size]; source.read(buffer, scripts[i].size); target.write(buffer, scripts[i].size); delete[] buffer; } source.close(); }
void TopMenu::loadBmpArr(Common::File &in) { arraySize = in.readUint16BE(); delete arrayBmp; arrayBmp = new Graphics::Surface *[arraySize * 2]; for (int i = 0; i < arraySize; i++) { uint16 bmpSize = in.readUint16BE(); uint32 filPos = in.pos(); Common::SeekableSubReadStream stream(&in, filPos, filPos + bmpSize); arrayBmp[i * 2] = Graphics::ImageDecoder::loadFile(stream, g_system->getOverlayFormat()); arrayBmp[i * 2 + 1] = new Graphics::Surface(); arrayBmp[i * 2 + 1]->create(arrayBmp[i * 2]->w * 2, arrayBmp[i * 2]->h * 2, arrayBmp[i * 2]->bytesPerPixel); byte *src = (byte *)arrayBmp[i * 2]->pixels; byte *dst = (byte *)arrayBmp[i * 2 + 1]->pixels; for (int j = 0; j < arrayBmp[i * 2]->h; j++) { src = (byte *)arrayBmp[i * 2]->getBasePtr(0, j); dst = (byte *)arrayBmp[i * 2 + 1]->getBasePtr(0, j * 2); for (int k = arrayBmp[i * 2]->w; k > 0; k--) { for (int m = arrayBmp[i * 2]->bytesPerPixel; m > 0; m--) { *dst++ = *src++; } src -= arrayBmp[i * 2]->bytesPerPixel; for (int m = arrayBmp[i * 2]->bytesPerPixel; m > 0; m--) { *dst++ = *src++; } } src = (byte *)arrayBmp[i * 2 + 1]->getBasePtr(0, j * 2); dst = (byte *)arrayBmp[i * 2 + 1]->getBasePtr(0, j * 2 + 1); for (int k = arrayBmp[i * 2 + 1]->pitch; k > 0; k--) { *dst++ = *src++; } } in.skip(bmpSize); } }
bool loadWAVFromStream(Common::File &stream, int &size, int &rate, byte &flags, uint16 *wavType, int *blockAlign_) { const uint32 initialPos = stream.pos(); byte buf[4+1]; buf[4] = 0; stream.read_noThrow(buf, 4); if (memcmp(buf, "RIFF", 4) != 0) { warning("getWavInfo: No 'RIFF' header"); return false; } uint32 wavLength = stream.readUint32LE(); stream.read_noThrow(buf, 4); if (memcmp(buf, "WAVE", 4) != 0) { warning("getWavInfo: No 'WAVE' header"); return false; } stream.read_noThrow(buf, 4); if (memcmp(buf, "fmt ", 4) != 0) { warning("getWavInfo: No 'fmt' header"); return false; } uint32 fmtLength = stream.readUint32LE(); if (fmtLength < 16) { // A valid fmt chunk always contains at least 16 bytes warning("getWavInfo: 'fmt' header is too short"); return false; } // Next comes the "type" field of the fmt header. Some typical // values for it: // 1 -> uncompressed PCM // 17 -> IMA ADPCM compressed WAVE // See <http://www.saettler.com/RIFFNEW/RIFFNEW.htm> for a more complete // list of common WAVE compression formats... uint16 type = stream.readUint16LE(); // == 1 for PCM data uint16 numChannels = stream.readUint16LE(); // 1 for mono, 2 for stereo uint32 samplesPerSec = stream.readUint32LE(); // in Hz uint32 avgBytesPerSec = stream.readUint32LE(); // == SampleRate * NumChannels * BitsPerSample/8 uint16 blockAlign = stream.readUint16LE(); // == NumChannels * BitsPerSample/8 uint16 bitsPerSample = stream.readUint16LE(); // 8, 16 ... // 8 bit data is unsigned, 16 bit data signed if (wavType != 0) *wavType = type; if (blockAlign_ != 0) *blockAlign_ = blockAlign; #if 0 printf("WAVE information:\n"); printf(" total size: %d\n", wavLength); printf(" fmt size: %d\n", fmtLength); printf(" type: %d\n", type); printf(" numChannels: %d\n", numChannels); printf(" samplesPerSec: %d\n", samplesPerSec); printf(" avgBytesPerSec: %d\n", avgBytesPerSec); printf(" blockAlign: %d\n", blockAlign); printf(" bitsPerSample: %d\n", bitsPerSample); #endif if (type != 1 && type != 2 && type != 17) { warning("getWavInfo: only PCM, MS ADPCM or IMA ADPCM data is supported (type %d)", type); return false; } if (blockAlign != numChannels * bitsPerSample / 8 && type != 2) { debug(0, "getWavInfo: blockAlign is invalid"); } if (avgBytesPerSec != samplesPerSec * blockAlign && type != 2) { debug(0, "getWavInfo: avgBytesPerSec is invalid"); } // Prepare the return values. rate = samplesPerSec; flags = 0; if (bitsPerSample == 8) // 8 bit data is unsigned flags |= Audio::Mixer::FLAG_UNSIGNED; else if (bitsPerSample == 16) // 16 bit data is signed little endian flags |= (Audio::Mixer::FLAG_16BITS | Audio::Mixer::FLAG_LITTLE_ENDIAN); else if (bitsPerSample == 4 && type == 17) // MS IMA ADPCM compressed. We decompress it flags |= (Audio::Mixer::FLAG_16BITS | Audio::Mixer::FLAG_LITTLE_ENDIAN); else if (bitsPerSample == 4 && type == 2) // MS ADPCM compressed. We decompress it flags |= (Audio::Mixer::FLAG_16BITS | Audio::Mixer::FLAG_LITTLE_ENDIAN); else { warning("getWavInfo: unsupported bitsPerSample %d", bitsPerSample); return false; } if (numChannels == 2) flags |= Audio::Mixer::FLAG_STEREO; else if (numChannels != 1) { warning("getWavInfo: unsupported number of channels %d", numChannels); return false; } // It's almost certainly a WAV file, but we still need to find its // 'data' chunk. // Skip over the rest of the fmt chunk. int offset = fmtLength - 16; do { stream.seek(offset, SEEK_CUR); if (stream.pos() >= int(initialPos + wavLength + 8)) { warning("getWavInfo: Cannot find 'data' chunk"); return false; } stream.read_noThrow(buf, 4); offset = stream.readUint32LE(); #if 0 printf(" found a '%s' tag of size %d\n", buf, offset); #endif } while (memcmp(buf, "data", 4) != 0); // Stream now points at 'offset' bytes of sample data... size = offset; return true; }
ADDetectedGame DirectorMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const { // TODO: Handle Mac fallback // reset fallback description Director::DirectorGameDescription *desc = &s_fallbackDesc; desc->desc.gameId = "director"; desc->desc.extra = ""; desc->desc.language = Common::UNK_LANG; desc->desc.flags = ADGF_NO_FLAGS; desc->desc.platform = Common::kPlatformWindows; desc->desc.guiOptions = GUIO0(); desc->desc.filesDescriptions[0].fileName = 0; desc->version = 0; desc->gameID = Director::GID_GENERIC; for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) { if (file->isDirectory()) continue; Common::String fileName = file->getName(); fileName.toLowercase(); if (!fileName.hasSuffix(".exe")) continue; Common::File f; if (!f.open(*file)) continue; f.seek(-4, SEEK_END); uint32 offset = f.readUint32LE(); if (f.eos() || offset == 0 || offset >= (uint32)(f.size() - 4)) continue; f.seek(offset); uint32 tag = f.readUint32LE(); switch (tag) { case MKTAG('3', '9', 'J', 'P'): desc->version = 4; break; case MKTAG('P', 'J', '9', '5'): desc->version = 5; break; case MKTAG('P', 'J', '0', '0'): desc->version = 7; break; default: // Prior to version 4, there was no tag here. So we'll use a bit of a // heuristic to detect. The first field is the entry count, of which // there should only be one. if ((tag & 0xFFFF) != 1) continue; f.skip(3); uint32 mmmSize = f.readUint32LE(); if (f.eos() || mmmSize == 0) continue; byte fileNameSize = f.readByte(); if (f.eos()) continue; f.skip(fileNameSize); byte directoryNameSize = f.readByte(); if (f.eos()) continue; f.skip(directoryNameSize); if (f.pos() != f.size() - 4) continue; // Assume v3 at this point (for now at least) desc->version = 3; } strncpy(s_fallbackFileNameBuffer, fileName.c_str(), 50); s_fallbackFileNameBuffer[50] = '\0'; desc->desc.filesDescriptions[0].fileName = s_fallbackFileNameBuffer; warning("Director fallback detection D%d", desc->version); return ADDetectedGame(&desc->desc); } return ADDetectedGame(); }
int main(int argc, char *argv[]) { GtkWidget *main_window, *scroll; GtkWidget *treeview; GtkTreeViewColumn *column; GtkCellRenderer *name_renderer, *size_renderer; GtkTreeStore *store; GtkTreeIter categories[14]; GValue value = { 0, }; gint offset; uint32 res_counts[14]; uint32 res_sizes[14]; int i; Common::File in; uint32 index_pos; uint32 pos, len; gtk_init(&argc, &argv); if (argc != 2) { printf("Usage: %s filename\n", argv[0]); return EXIT_FAILURE; } in.open(argv[1], "rb"); if (!in.isOpen()) { printf("Couldn't open %s for reading\n", argv[1]); return EXIT_FAILURE; } /* Create the main window, scrollable in both directions */ main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(main_window), "CLUster Explorer"); gtk_window_set_default_size(GTK_WINDOW(main_window), 400, 400); g_signal_connect(G_OBJECT(main_window), "destroy", G_CALLBACK(main_window_destroy_cb), NULL); scroll = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll), GTK_SHADOW_ETCHED_IN); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); /* Create the tree view */ for (i = 0; i < ARRAYSIZE(res_counts); i++) { res_counts[i] = 0; res_sizes[i] = 0; } store = gtk_tree_store_new(N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT); gtk_tree_sortable_set_default_sort_func(GTK_TREE_SORTABLE(store), compare_items, NULL, NULL); gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store), GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, GTK_SORT_ASCENDING); index_pos = in.readUint32LE(); in.seek(index_pos, SEEK_SET); for (;;) { GtkTreeIter iter; byte type; gchar *utf8_name; gchar name[34]; gchar *size; try { pos = in.readUint32LE(); len = in.readUint32LE(); } catch (...) { break; } size = make_size(len); index_pos = in.pos(); in.seek(pos, SEEK_SET); type = in.readByte(); in.readByte(); /* compType */ in.readUint32LE(); /* compSize */ in.readUint32LE(); /* decompSize */ in.read_noThrow(name, sizeof(name)); /* * We need to convert from Latin-1 to UTF-8. Otherwise the text * "CAFÉ" won't be displayed properly. */ utf8_name = g_convert(name, -1, "UTF-8", "ISO-8859-1", NULL, NULL, NULL); if (!res_counts[type]) { gtk_tree_store_append(store, &categories[type], NULL); gtk_tree_store_set(store, &categories[type], NAME_COLUMN, getType(type), SIZE_COLUMN, "", TYPE_COLUMN, -1, POSITION_COLUMN, -1, LENGTH_COLUMN, -1, -1); } res_counts[type]++; res_sizes[type] += len; gtk_tree_store_append(store, &iter, &categories[type]); gtk_tree_store_set(store, &iter, NAME_COLUMN, utf8_name, SIZE_COLUMN, size, TYPE_COLUMN, type, POSITION_COLUMN, pos, LENGTH_COLUMN, len); in.seek(index_pos, SEEK_SET); } in.close(); for (i = 0; i < ARRAYSIZE(res_counts); i++) { if (res_counts[i]) { gchar size[80]; sprintf(size, "%s [%d]", make_size(res_sizes[i]), res_counts[i]); gtk_tree_store_set(store, &categories[i], SIZE_COLUMN, size, -1); } } treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), TRUE); g_signal_connect(G_OBJECT(treeview), "button-press-event", G_CALLBACK(tree_view_button_cb), argv[1]); /* The view now holds a reference. We can get rid of our own. */ g_object_unref(G_OBJECT(store)); name_renderer = gtk_cell_renderer_text_new(); size_renderer = gtk_cell_renderer_text_new(); g_value_init(&value, G_TYPE_FLOAT); g_value_set_float(&value, 1.0); g_object_set_property(G_OBJECT(size_renderer), "xalign", &value); gtk_tree_view_insert_column_with_attributes( GTK_TREE_VIEW(treeview), -1, "Name", name_renderer, "text", NAME_COLUMN, NULL); offset = gtk_tree_view_insert_column_with_attributes( GTK_TREE_VIEW(treeview), -1, "Size", size_renderer, "text", SIZE_COLUMN, NULL); column = gtk_tree_view_get_column(GTK_TREE_VIEW(treeview), offset - 1); gtk_tree_view_column_set_alignment(column, 1.0); gtk_container_add(GTK_CONTAINER(scroll), GTK_WIDGET(treeview)); gtk_container_add(GTK_CONTAINER(main_window), scroll); gtk_widget_show_all(GTK_WIDGET(main_window)); gtk_main(); return EXIT_SUCCESS; }
bool TonyEngine::loadTonyDat() { Common::String msg; Common::File in; in.open("tony.dat"); if (!in.isOpen()) { msg = "You're missing the 'tony.dat' file. Get it from the ScummVM website"; GUIErrorMessage(msg); warning("%s", msg.c_str()); return false; } // Read header char buf[4+1]; in.read(buf, 4); buf[4] = '\0'; if (strcmp(buf, "TONY")) { msg = "File 'tony.dat' is corrupt. Get it from the ScummVM website"; GUIErrorMessage(msg); warning("%s", msg.c_str()); return false; } int majVer = in.readByte(); int minVer = in.readByte(); if ((majVer != TONY_DAT_VER_MAJ) || (minVer != TONY_DAT_VER_MIN)) { msg = Common::String::format("File 'tony.dat' is wrong version. Expected %d.%d but got %d.%d. Get it from the ScummVM website", TONY_DAT_VER_MAJ, TONY_DAT_VER_MIN, majVer, minVer); GUIErrorMessage(msg); warning("%s", msg.c_str()); return false; } int expectedLangVariant = -1; switch (g_vm->getLanguage()) { case Common::IT_ITA: case Common::EN_ANY: expectedLangVariant = 0; break; case Common::PL_POL: expectedLangVariant = 1; break; case Common::RU_RUS: expectedLangVariant = 2; break; case Common::CZ_CZE: expectedLangVariant = 3; break; case Common::FR_FRA: expectedLangVariant = 4; break; case Common::DE_DEU: expectedLangVariant = 5; break; default: warning("Unhandled language, falling back to English/Italian fonts."); expectedLangVariant = 0; break; } int numVariant = in.readUint16BE(); if (expectedLangVariant > numVariant - 1) { msg = Common::String::format("Font variant not present in 'tony.dat'. Get it from the ScummVM website"); GUIErrorMessage(msg); warning("%s", msg.c_str()); return false; } in.seek(in.pos() + (2 * 256 * 8 * expectedLangVariant)); for (int i = 0; i < 256; i++) { _cTableDialog[i] = in.readSint16BE(); _lTableDialog[i] = in.readSint16BE(); _cTableMacc[i] = in.readSint16BE(); _lTableMacc[i] = in.readSint16BE(); _cTableCred[i] = in.readSint16BE(); _lTableCred[i] = in.readSint16BE(); _cTableObj[i] = in.readSint16BE(); _lTableObj[i] = in.readSint16BE(); } return true; }
/** * Opens and inits all MIDI sequence files. */ void OpenMidiFiles() { Common::File midiStream; if (TinselV0) { // The early demo version of DW1 doesn't have MIDI } else if (TinselV2) { // DW2 uses a different music mechanism } else if (TinselV1Mac) { // open MIDI sequence file in binary mode if (!midiStream.open(MIDI_FILE)) error(CANNOT_FIND_FILE, MIDI_FILE); uint32 curTrack = 1; uint32 songLength = 0; int32 fileSize = midiStream.size(); // Init for (int i = 0; i < ARRAYSIZE(g_midiOffsets); i++) g_midiOffsets[i] = 0; midiStream.skip(4); // skip file header while (!midiStream.eos() && !midiStream.err() && midiStream.pos() != fileSize) { assert(curTrack < ARRAYSIZE(g_midiOffsets)); g_midiOffsets[curTrack] = midiStream.pos(); //debug("%d: %d", curTrack, g_midiOffsets[curTrack]); songLength = midiStream.readUint32BE(); midiStream.skip(songLength); curTrack++; } midiStream.close(); } else { if (g_midiBuffer.pDat) // already allocated return; // open MIDI sequence file in binary mode if (!midiStream.open(MIDI_FILE)) error(CANNOT_FIND_FILE, MIDI_FILE); // get length of the largest sequence g_midiBuffer.size = midiStream.readUint32LE(); if (midiStream.eos() || midiStream.err()) error(FILE_IS_CORRUPT, MIDI_FILE); if (g_midiBuffer.size) { // allocate a buffer big enough for the largest MIDI sequence if ((g_midiBuffer.pDat = (uint8 *)malloc(g_midiBuffer.size)) != NULL) { // clear out the buffer memset(g_midiBuffer.pDat, 0, g_midiBuffer.size); } } // Now scan through the contents of the MIDI file to find the offset // of each individual track, in order to create a mapping from MIDI // offset to track number, for the enhanced MIDI soundtrack. // The first song is always at position 4. The subsequent ones are // calculated dynamically. uint32 curOffset = 4; uint32 curTrack = 0; uint32 songLength = 0; // Init for (int i = 0; i < ARRAYSIZE(g_midiOffsets); i++) g_midiOffsets[i] = 0; while (!midiStream.eos() && !midiStream.err()) { if (curOffset + (4 * curTrack) >= (uint32)midiStream.size()) break; assert(curTrack < ARRAYSIZE(g_midiOffsets)); g_midiOffsets[curTrack] = curOffset + (4 * curTrack); //debug("%d: %d", curTrack, midiOffsets[curTrack]); songLength = midiStream.readUint32LE(); curOffset += songLength; midiStream.skip(songLength); curTrack++; } midiStream.close(); } }
bool PCMMusicPlayer::getNextChunk() { MusicSegment *musicSegments; int32 *script, *scriptBuffer; int id; int snum; uint32 sampleOffset, sampleLength, sampleCLength; Common::File file; byte *buffer; Common::SeekableReadStream *sampleStream; switch (_state) { case S_NEW: case S_NEXT: _forcePlay = false; script = scriptBuffer = (int32 *)LockMem(_hScript); // Set parameters for this chunk of music id = _scriptNum; while (id--) script = scriptBuffer + READ_32(script); snum = FROM_32(script[_scriptIndex++]); if (snum == MUSIC_JUMP || snum == MUSIC_END) { // Let usual code sort it out! _scriptIndex--; // Undo increment _forcePlay = true; // Force a Play _state = S_END1; // 'Goto' S_END1 break; } musicSegments = (MusicSegment *) LockMem(_hSegment); assert(FROM_32(musicSegments[snum].numChannels) == 1); assert(FROM_32(musicSegments[snum].bitsPerSample) == 16); sampleOffset = FROM_32(musicSegments[snum].sampleOffset); sampleLength = FROM_32(musicSegments[snum].sampleLength); sampleCLength = (((sampleLength + 63) & ~63)*33)/64; if (!file.open(_filename)) error(CANNOT_FIND_FILE, _filename.c_str()); file.seek(sampleOffset); if (file.eos() || file.err() || (uint32)file.pos() != sampleOffset) error(FILE_IS_CORRUPT, _filename.c_str()); buffer = (byte *) malloc(sampleCLength); assert(buffer); // read all of the sample if (file.read(buffer, sampleCLength) != sampleCLength) error(FILE_IS_CORRUPT, _filename.c_str()); debugC(DEBUG_DETAILED, kTinselDebugMusic, "Creating ADPCM music chunk with size %d, " "offset %d (script %d.%d)", sampleCLength, sampleOffset, _scriptNum, _scriptIndex - 1); sampleStream = new Common::MemoryReadStream(buffer, sampleCLength, DisposeAfterUse::YES); delete _curChunk; _curChunk = new Tinsel8_ADPCMStream(sampleStream, DisposeAfterUse::YES, sampleCLength, 22050, 1, 32); _state = S_MID; return true; case S_END1: debugC(DEBUG_DETAILED, kTinselDebugMusic, "Music reached state S_END1 (script %d.%d)", _scriptNum, _scriptIndex); script = scriptBuffer = (int32 *) LockMem(_hScript); id = _scriptNum; while (id--) script = scriptBuffer + READ_32(script); snum = FROM_32(script[_scriptIndex]); if (snum == MUSIC_END) { _state = S_END2; } else { if (snum == MUSIC_JUMP) _scriptIndex = FROM_32(script[_scriptIndex+1]); _state = _forcePlay ? S_NEW : S_NEXT; _forcePlay = false; } return true; case S_END2: debugC(DEBUG_DETAILED, kTinselDebugMusic, "Music reached state S_END2 (script %d.%d)", _scriptNum, _scriptIndex); _silenceSamples = 11025; // Half a second of silence return true; case S_END3: debugC(DEBUG_DETAILED, kTinselDebugMusic, "Music reached state S_END3 (script %d.%d)", _scriptNum, _scriptIndex); stop(); _state = S_IDLE; return false; case S_IDLE: return false; default: break; } return true; }
static Common::SeekableReadStream *readImage_NIB(const Common::String &filename) { Common::File f; if (!f.open(filename)) return nullptr; if (f.size() != 232960) error("Unrecognized NIB image '%s' of size %d bytes", filename.c_str(), f.size()); // starting at 0xaa, 32 is invalid (see below) const byte c_5and3_lookup[] = { 32, 0, 32, 1, 2, 3, 32, 32, 32, 32, 32, 4, 5, 6, 32, 32, 7, 8, 32, 9, 10, 11, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 12, 13, 32, 32, 14, 15, 32, 16, 17, 18, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 19, 20, 32, 21, 22, 23, 32, 32, 32, 32, 32, 24, 25, 26, 32, 32, 27, 28, 32, 29, 30, 31 }; // starting at 0x96, 64 is invalid (see below) const byte c_6and2_lookup[] = { 0, 1, 64, 64, 2, 3, 64, 4, 5, 6, 64, 64, 64, 64, 64, 64, 7, 8, 64, 64, 64, 9, 10, 11, 12, 13, 64, 64, 14, 15, 16, 17, 18, 19, 64, 20, 21, 22, 23, 24, 25, 26, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 27, 64, 28, 29, 30, 64, 64, 64, 31, 64, 64, 32, 33, 64, 34, 35, 36, 37, 38, 39, 40, 64, 64, 64, 64, 64, 41, 42, 43, 64, 44, 45, 46, 47, 48, 49, 50, 64, 64, 51, 52, 53, 54, 55, 56, 64, 57, 58, 59, 60, 61, 62, 63 }; // we always pad it out const uint sectorsPerTrack = 16; const uint bytesPerSector = 256; const uint imageSize = 35 * sectorsPerTrack * bytesPerSector; byte *const diskImage = (byte *)calloc(imageSize, 1); bool sawAddress = false; uint8 volNo, track, sector; bool newStyle; byte buffer[trackLen]; uint firstGoodTrackPos = 0; uint pos = trackLen; // force read while (true) { if (pos >= trackLen+firstGoodTrackPos) { if (f.pos() == f.size()) break; f.read(buffer, sizeof(buffer)); firstGoodTrackPos = 0; pos = 0; sawAddress = false; } // Read until we find two sync bytes. if (buffer[pos++ % trackLen] != 0xd5 || buffer[pos++ % trackLen] != 0xaa) continue; byte prologue = buffer[pos++ % trackLen]; if (sawAddress && (prologue == 0xb5 || prologue == 0x96)) { sawAddress = false; } if (!sawAddress) { sawAddress = true; newStyle = false; // We should always find the address field first. if (prologue != 0xb5) { // Accept a DOS 3.3(?) header at the start. if (prologue == 0x96) { newStyle = true; } else if (prologue == 0xad || prologue == 0xfd) { sawAddress = false; continue; } else { error("unknown NIB field prologue %02x", prologue); } } volNo = read44(buffer, pos); track = read44(buffer, pos); sector = read44(buffer, pos); uint8 checksum = read44(buffer, pos); if ((volNo ^ track ^ sector) != checksum) { warning("invalid NIB checksum (volNo %d, track %d, sector %d)", volNo, track, sector); sawAddress = false; continue; } if (!firstGoodTrackPos) firstGoodTrackPos = pos; // Epilogue is de/aa plus a gap, but we don't care. continue; } sawAddress = false; // We should always find the data field after an address field. // TODO: we ignore volNo? byte *output = diskImage + (track * sectorsPerTrack + sector) * bytesPerSector; if (newStyle) { // We hardcode the DOS 3.3 mapping here. TODO: Do we also need raw/prodos? int raw2dos[16] = { 0, 7, 14, 6, 13, 5, 12, 4, 11, 3, 10, 2, 9, 1, 8, 15 }; sector = raw2dos[sector]; output = diskImage + (track * sectorsPerTrack + sector) * bytesPerSector; // 6-and-2 uses 342 on-disk bytes byte inbuffer[342]; uint z = trackLen - (pos % trackLen); if (z < 342) { memcpy(inbuffer, buffer + (pos % trackLen), z); memcpy(inbuffer + z, buffer, 342 - z); } else memcpy(inbuffer, buffer + (pos % trackLen), 342); pos += 342; byte oldVal = 0; for (uint n = 0; n < 342; ++n) { // expand assert(inbuffer[n] >= 0x96); // corrupt file (TODO: assert?) byte val = c_6and2_lookup[inbuffer[n] - 0x96]; if (val == 0x40) { error("NIB: invalid nibble value %02x", inbuffer[n]); } // undo checksum oldVal = val ^ oldVal; inbuffer[n] = oldVal; } byte checksum = buffer[pos++ % trackLen]; if (checksum < 0x96 || oldVal != c_6and2_lookup[checksum - 0x96]) warning("NIB: checksum mismatch @ (%x, %x)", track, sector); for (uint n = 0; n < 256; ++n) { output[n] = inbuffer[86 + n] << 2; if (n < 86) { // use first pair of bits output[n] |= ((inbuffer[n] & 1) << 1); output[n] |= ((inbuffer[n] & 2) >> 1); } else if (n < 86*2) { // second pair output[n] |= ((inbuffer[n-86] & 4) >> 1); output[n] |= ((inbuffer[n-86] & 8) >> 3); } else { // third pair