ZorkCursor::ZorkCursor(const Common::String &fileName) : _width(0), _height(0), _hotspotX(0), _hotspotY(0) { Common::File file; if (!file.open(fileName)) return; uint32 magic = file.readUint32BE(); if (magic != MKTAG('Z', 'C', 'R', '1')) { warning("%s is not a Zork Cursor file", fileName.c_str()); return; } _hotspotX = file.readUint16LE(); _hotspotY = file.readUint16LE(); _width = file.readUint16LE(); _height = file.readUint16LE(); uint dataSize = _width * _height * sizeof(uint16); _surface.create(_width, _height, Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0)); uint32 bytesRead = file.read(_surface.getPixels(), dataSize); assert(bytesRead == dataSize); // Convert to RGB 565 _surface.convertToInPlace(Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0)); }
InventoryData *Resource::readInventory(const Common::String fileName) { Common::File *dataFile = openDataFile(fileName, MKTAG('I', 'N', 'V', '1')); _vm->_numInv = dataFile->readUint16LE(); InventoryData *inventory = new InventoryData[_vm->_numInv + 1]; for (int i = 1; i <= _vm->_numInv; i++) { inventory[i]._quantity = dataFile->readUint16LE(); inventory[i]._name = readString(dataFile); inventory[i]._bitmapName = readString(dataFile); } delete dataFile; return inventory; }
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; }
/** * 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; }
Common::SeekableReadStream *Hqr::createReadStreamForIndex(int index) const { if (index >= _numIndices) return 0; uint32 realSize; uint32 compressedSize; uint16 mode; Common::File *file = new Common::File(); file->open(_hqrFileName); file->seek(_indices[index]); realSize = file->readUint32LE(); compressedSize = file->readUint32LE(); mode = file->readUint16LE(); uint32 begin = _indices[index] + 10; uint32 end = 0; if (mode == 0) { end = begin + realSize; } else { end = begin + compressedSize; } Common::SeekableReadStream *stream = new Common::SeekableSubReadStream(file, begin, end, DisposeAfterUse::YES); if (mode != 0) { stream = new LzssReadStream(stream, mode, realSize); } return stream; }
// AUDIOnnn.MAP contains 10-byte entries: // Early format: // w 5 bits resource type and 11 bits resource number // dw 7 bits volume number and 25 bits offset // dw size // Later format: // w nEntry // dw offset+volume (as in resource.map) // dw size // ending with 10 0xFFs int ResourceManager::readAudioMapSCI1(ResourceSource *map, bool unload) { Common::File file; if (!file.open(map->getLocationName())) return SCI_ERROR_RESMAP_NOT_FOUND; bool oldFormat = (file.readUint16LE() >> 11) == kResourceTypeAudio; file.seek(0); for (;;) { uint16 n = file.readUint16LE(); uint32 offset = file.readUint32LE(); uint32 size = file.readUint32LE(); if (file.eos() || file.err()) { warning("Error while reading %s", map->getLocationName().c_str()); return SCI_ERROR_RESMAP_NOT_FOUND; } if (n == 0xffff) break; byte volume_nr; if (oldFormat) { n &= 0x07ff; // Mask out resource type volume_nr = offset >> 25; // most significant 7 bits offset &= 0x01ffffff; // least significant 25 bits } else { volume_nr = offset >> 28; // most significant 4 bits offset &= 0x0fffffff; // least significant 28 bits } ResourceSource *src = findVolume(map, volume_nr); if (src) { const ResourceId resId(kResourceTypeAudio, n); if (unload) removeAudioResource(resId); else addResource(resId, src, offset, size, map->getLocationName()); } else { warning("Failed to find audio volume %i", volume_nr); return SCI_ERROR_NO_RESOURCE_FILES_FOUND; } }
Common::SeekableReadStream *MADSResourceManager::loadResource(const char *resourceName, bool loadFlag) { Common::File hagFile; uint32 offset = 0, size = 0; // If the first character is a '@' then look for an external file if (*resourceName == '@') { ++resourceName; hagFile.open(resourceName); if (loadFlag) return hagFile.readStream(hagFile.size()); else return new Common::SeekableSubReadStream(&hagFile, 0, hagFile.size()); } // If the first character is the wildcard (resource indicator), skip over it if (*resourceName == '*') ++resourceName; char resName[20]; strcpy(resName, resourceName); str_upper(resName); hagFile.open(getResourceFilename(resName)); // Validate hag file header char headerBuffer[16]; if ((hagFile.read(headerBuffer, 16) != 16) || (strncmp(headerBuffer, madsConcatString, 10) != 0)) error("Invalid HAG file opened"); int numEntries = hagFile.readUint16LE(); int resIndex = -1; while (++resIndex < numEntries) { // Read in the details of the next resource char resourceBuffer[14]; offset = hagFile.readUint32LE(); size = hagFile.readUint32LE(); hagFile.read(resourceBuffer, 14); if (!strcmp(resName, resourceBuffer)) break; } if (resIndex == numEntries) error("Invalid resource '%s' specified", resourceName); // Get the resource, either loading it in it's entirely or getting a stream reference if (loadFlag) { hagFile.seek(offset); return hagFile.readStream(size); } else { return new Common::SeekableSubReadStream(&hagFile, offset, offset + size); } }
void Resource::readRoomData(const Common::String fileName) { Common::File *dataFile = openDataFile(fileName, MKTAG('D', 'O', 'R', '1')); _vm->_manyRooms = dataFile->readUint16LE(); _vm->_highestCondition = dataFile->readUint16LE(); _vm->_rooms = new RoomData[_vm->_manyRooms + 1]; for (int i = 1; i <= _vm->_manyRooms; i++) { RoomData *curRoom = &_vm->_rooms[i]; curRoom->_doors[kDirectionNorth] = dataFile->readUint16LE(); curRoom->_doors[kDirectionSouth] = dataFile->readUint16LE(); curRoom->_doors[kDirectionEast] = dataFile->readUint16LE(); curRoom->_doors[kDirectionWest] = dataFile->readUint16LE(); curRoom->_transitionType = dataFile->readByte(); } delete dataFile; }
Font::Font(Common::String filename) { const uint32 headerFont = MKTAG('T', 'F', 'F', '\0'); Common::File stream; stream.open(filename); uint32 header = stream.readUint32BE(); if (header != headerFont) error("Invalid resource - %s", filename.c_str()); stream.skip(4); // total memory _count = stream.readUint16LE(); _first = stream.readUint16LE(); _last = stream.readUint16LE(); _width = stream.readUint16LE(); _height = stream.readUint16LE(); _fontSurface.create(_width * _count, _height, ::Graphics::PixelFormat::createFormatCLUT8()); byte cur; int bitIndex = 7; byte *p; cur = stream.readByte(); for (uint n = 0; n < _count; n++) { for (uint y = 0; y < _height; y++) { p = (byte *)_fontSurface.getBasePtr(n * _width, y); for (uint x = n * _width; x < n * _width + _width; x++) { *p++ = (cur & (1 << bitIndex)) ? 0 : 0xFF; bitIndex--; if (bitIndex < 0) { bitIndex = 7; cur = stream.readByte(); } } } } }
/** * 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; }
TextFont *Resource::getFont(const Common::String fileName) { // TODO: Add support for the font format of the Amiga version Common::File *dataFile = openDataFile(fileName, MKTAG('V', 'G', 'A', 'F')); uint32 headerSize = 4 + 2 + 256 * 3 + 4; uint32 fileSize = dataFile->size(); if (fileSize <= headerSize) return nullptr; TextFont *textfont = new TextFont(); textfont->_dataLength = fileSize - headerSize; textfont->_height = dataFile->readUint16LE(); dataFile->read(textfont->_widths, 256); for (int i = 0; i < 256; i++) textfont->_offsets[i] = dataFile->readUint16LE(); dataFile->skip(4); textfont->_data = new byte[textfont->_dataLength + 4]; dataFile->read(textfont->_data, textfont->_dataLength); delete dataFile; return textfont; }
void LabEngine::loadMapData() { Common::File *mapImages = _resource->openDataFile("P:MapImage"); _imgMap = new Image(mapImages, this); _imgRoom = new Image(mapImages, this); _imgUpArrowRoom = new Image(mapImages, this); _imgDownArrowRoom = new Image(mapImages, this); _imgHRoom = new Image(mapImages, this); _imgVRoom = new Image(mapImages, this); _imgMaze = new Image(mapImages, this); _imgHugeMaze = new Image(mapImages, this); _imgMapX[kDirectionNorth] = new Image(mapImages, this); _imgMapX[kDirectionEast] = new Image(mapImages, this); _imgMapX[kDirectionSouth] = new Image(mapImages, this); _imgMapX[kDirectionWest] = new Image(mapImages, this); _imgPath = new Image(mapImages, this); _imgBridge = new Image(mapImages, this); _mapButtonList.push_back(_interface->createButton( 8, _utils->vgaScaleY(105), 0, Common::KEYCODE_ESCAPE, new Image(mapImages, this), new Image(mapImages, this))); // back _mapButtonList.push_back(_interface->createButton( 55, _utils->vgaScaleY(105), 1, Common::KEYCODE_UP, new Image(mapImages, this), new Image(mapImages, this))); // up _mapButtonList.push_back(_interface->createButton(101, _utils->vgaScaleY(105), 2, Common::KEYCODE_DOWN, new Image(mapImages, this), new Image(mapImages, this))); // down delete mapImages; Common::File *mapFile = _resource->openDataFile("Lab:Maps", MKTAG('M', 'A', 'P', '0')); updateEvents(); _maxRooms = mapFile->readUint16LE(); _maps = new MapData[_maxRooms + 1]; // will be freed when the user exits the map for (int i = 0; i <= _maxRooms; i++) { _maps[i]._x = mapFile->readUint16LE(); _maps[i]._y = mapFile->readUint16LE(); _maps[i]._pageNumber = mapFile->readUint16LE(); _maps[i]._specialID = (SpecialRoom) mapFile->readUint16LE(); _maps[i]._mapFlags = mapFile->readUint32LE(); } delete mapFile; }
bool ScummDebugger::Cmd_ImportRes(int argc, const char** argv) { Common::File file; uint32 size; int resnum; if (argc != 4) { DebugPrintf("Syntax: importres <restype> <filename> <resnum>\n"); return true; } resnum = atoi(argv[3]); // FIXME add bounds check if (!strncmp(argv[1], "scr", 3)) { file.open(argv[2], Common::File::kFileReadMode); if (file.isOpen() == false) { DebugPrintf("Could not open file %s\n", argv[2]); return true; } if (_vm->_game.features & GF_SMALL_HEADER) { size = file.readUint16LE(); file.seek(-2, SEEK_CUR); } else if (_vm->_game.features & GF_SMALL_HEADER) { if (_vm->_game.version == 4) file.seek(8, SEEK_CUR); size = file.readUint32LE(); file.readUint16LE(); file.seek(-6, SEEK_CUR); } else { file.readUint32BE(); size = file.readUint32BE(); file.seek(-8, SEEK_CUR); } file.read(_vm->res.createResource(rtScript, resnum, size), size); } else DebugPrintf("Unknown importres type '%s'\n", argv[1]); return true; }
void Music::loadSoundEffect(const Common::String filename, bool loop, bool waitTillFinished) { stopSoundEffect(); Common::File *file = _vm->_resource->openDataFile(filename, MKTAG('D', 'I', 'F', 'F')); if (!file) return; _vm->_anim->_doBlack = false; uint32 magicBytes = file->readUint32LE(); if (magicBytes != 1219009121) { warning("readSound: Bad signature, skipping"); return; } uint32 soundTag = file->readUint32LE(); uint32 soundSize = file->readUint32LE(); if (soundTag != 0) return; file->skip(soundSize); // skip the header while (soundTag != 65535) { _vm->updateEvents(); soundTag = file->readUint32LE(); soundSize = file->readUint32LE() - 8; if ((soundTag == 30) || (soundTag == 31)) { if (waitTillFinished) { while (isSoundEffectActive()) { _vm->updateEvents(); _vm->waitTOF(); } } file->skip(4); uint16 sampleRate = file->readUint16LE(); file->skip(2); playSoundEffect(sampleRate, soundSize, loop, file); } else if (soundTag == 65535) { if (waitTillFinished) { while (isSoundEffectActive()) { _vm->updateEvents(); _vm->waitTOF(); } } } else file->skip(soundSize); } }
/** * Reads boot file for program environment. Fatal error if not there or * file checksum is bad. De-crypts structure while checking checksum */ void FileManager::readBootFile() { debugC(1, kDebugFile, "readBootFile()"); Common::File ofp; if (!ofp.open(getBootFilename())) { if (_vm->_gameVariant == kGameVariantH1Dos) { //TODO initialize properly _boot structure warning("readBootFile - Skipping as H1 Dos may be a freeware"); memset(_vm->_boot._distrib, '\0', sizeof(_vm->_boot._distrib)); _vm->_boot._registered = kRegFreeware; return; } else if (_vm->getPlatform() == Common::kPlatformPC) { warning("readBootFile - Skipping as H2 and H3 Dos may be shareware"); memset(_vm->_boot._distrib, '\0', sizeof(_vm->_boot._distrib)); _vm->_boot._registered = kRegShareware; return; } else { Utils::notifyBox(Common::String::format("Missing startup file '%s'", getBootFilename())); _vm->getGameStatus()._doQuitFl = true; return; } } if (ofp.size() < (int32)sizeof(_vm->_boot)) { Utils::notifyBox(Common::String::format("Corrupted startup file '%s'", getBootFilename())); _vm->getGameStatus()._doQuitFl = true; return; } _vm->_boot._checksum = ofp.readByte(); _vm->_boot._registered = ofp.readByte(); ofp.read(_vm->_boot._pbswitch, sizeof(_vm->_boot._pbswitch)); ofp.read(_vm->_boot._distrib, sizeof(_vm->_boot._distrib)); _vm->_boot._exitLen = ofp.readUint16LE(); byte *p = (byte *)&_vm->_boot; byte checksum = 0; for (uint32 i = 0; i < sizeof(_vm->_boot); i++) { checksum ^= p[i]; p[i] ^= s_bootCypher[i % s_bootCypherLen]; } ofp.close(); if (checksum) { Utils::notifyBox(Common::String::format("Corrupted startup file '%s'", getBootFilename())); _vm->getGameStatus()._doQuitFl = true; } }
/** * Read sound (or music) file data. Call with SILENCE to free-up * any allocated memory. Also returns size of data */ SoundPtr FileManager::getSound(const int16 sound, uint16 *size) { debugC(1, kDebugFile, "getSound(%d)", sound); // No more to do if SILENCE (called for cleanup purposes) if (sound == _vm->_soundSilence) return 0; // Open sounds file Common::File fp; // Handle to SOUND_FILE if (!fp.open(getSoundFilename())) { warning("Hugo Error: File not found %s", getSoundFilename()); return 0; } if (!_hasReadHeader) { for (int i = 0; i < kMaxSounds; i++) { _soundHdr[i]._size = fp.readUint16LE(); _soundHdr[i]._offset = fp.readUint32LE(); } if (fp.err()) error("Wrong sound file format"); _hasReadHeader = true; } *size = _soundHdr[sound]._size; if (*size == 0) error("Wrong sound file format or missing sound %d", sound); // Allocate memory for sound or music, if possible SoundPtr soundPtr = (byte *)malloc(_soundHdr[sound]._size); // Ptr to sound data assert(soundPtr); // Seek to data and read it fp.seek(_soundHdr[sound]._offset, SEEK_SET); if (fp.read(soundPtr, _soundHdr[sound]._size) != _soundHdr[sound]._size) error("Wrong sound file format"); fp.close(); return soundPtr; }
bool MADSResourceManager::resourceExists(const char *resourceName) { Common::File hagFile; uint32 offset, size; // If the first character is the wildcard (resource indicator), skip over it if (*resourceName == '*') ++resourceName; char resName[20]; strcpy(resName, resourceName); str_upper(resName); hagFile.open(getResourceFilename(resName)); // Validate hag file header char headerBuffer[16]; if ((hagFile.read(headerBuffer, 16) != 16) || (strncmp(headerBuffer, madsConcatString, 10) != 0)) error("Invalid HAG file opened"); int numEntries = hagFile.readUint16LE(); int resIndex = -1; while (++resIndex < numEntries) { // Read in the details of the next resource char resourceBuffer[14]; offset = hagFile.readUint32LE(); size = hagFile.readUint32LE(); hagFile.read(resourceBuffer, 14); if (!strcmp(resName, resourceBuffer)) break; } if (resIndex == numEntries) return false; else return true; }
/** * Returns address of uif_hdr[id], reading it in if first call * This file contains, between others, the bitmaps of the fonts used in the application * UIF means User interface database (Windows Only) */ UifHdr *FileManager::getUIFHeader(const Uif id) { debugC(1, kDebugFile, "getUIFHeader(%d)", id); // Initialize offset lookup if not read yet if (_firstUIFFl) { _firstUIFFl = false; // Open unbuffered to do far read Common::File ip; // Image data file if (!ip.open(getUifFilename())) error("File not found: %s", getUifFilename()); if (ip.size() < (int32)sizeof(_UIFHeader)) error("Wrong UIF file format"); for (int i = 0; i < kMaxUifs; ++i) { _UIFHeader[i]._size = ip.readUint16LE(); _UIFHeader[i]._offset = ip.readUint32LE(); } ip.close(); } return &_UIFHeader[id]; }
/** * Reads boot file for program environment. Fatal error if not there or * file checksum is bad. De-crypts structure while checking checksum */ void FileManager::readBootFile() { debugC(1, kDebugFile, "readBootFile()"); Common::File ofp; if (!ofp.open(getBootFilename())) { if (_vm->_gameVariant == kGameVariantH1Dos) { //TODO initialize properly _boot structure warning("readBootFile - Skipping as H1 Dos may be a freeware"); memset(_vm->_boot.distrib, '\0', sizeof(_vm->_boot.distrib)); _vm->_boot.registered = kRegFreeware; return; } else { error("Missing startup file '%s'", getBootFilename()); } } if (ofp.size() < (int32)sizeof(_vm->_boot)) error("Corrupted startup file"); _vm->_boot.checksum = ofp.readByte(); _vm->_boot.registered = ofp.readByte(); ofp.read(_vm->_boot.pbswitch, sizeof(_vm->_boot.pbswitch)); ofp.read(_vm->_boot.distrib, sizeof(_vm->_boot.distrib)); _vm->_boot.exit_len = ofp.readUint16LE(); byte *p = (byte *)&_vm->_boot; byte checksum = 0; for (uint32 i = 0; i < sizeof(_vm->_boot); i++) { checksum ^= p[i]; p[i] ^= s_bootCyper[i % s_bootCyperLen]; } ofp.close(); if (checksum) error("Corrupted startup file"); }
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; }
/** * Loads and draws the chosen page of the help. * @remarks Originally called 'getme' */ void Help::switchPage(byte which) { // Help icons are 80x20. _highlightWas = 177; // Forget where the highlight was. Common::File file; if (!file.open("help.avd")) error("AVALANCHE: Help: File not found: help.avd"); file.seek(which * 2); uint16 offset = file.readUint16LE(); file.seek(offset); Common::String title = getLine(file); _vm->_graphics->drawFilledRectangle(Common::Rect(0, 0, 640, 200), kColorBlue); _vm->_graphics->drawFilledRectangle(Common::Rect(8, 40, 450, 200), kColorWhite); byte index = file.readByte(); _vm->_graphics->helpDrawButton(-177, index); // Plot the title: _vm->_graphics->drawNormalText(title, _vm->_font, 8, 629 - 8 * title.size(), 26, kColorBlack); _vm->_graphics->drawNormalText(title, _vm->_font, 8, 630 - 8 * title.size(), 25, kColorCyan); _vm->_graphics->helpDrawBigText("help!", 549, 1, kColorBlack); _vm->_graphics->helpDrawBigText("help!", 550, 0, kColorCyan); byte y = 0; do { Common::String line = getLine(file); if (!line.empty()) { if (line.compareTo(Common::String('!')) == 0) // End of the help text is signalled with a '!'. break; if (line[0] == '\\') { line.deleteChar(0); _vm->_graphics->drawNormalText(line, _vm->_font, 8, 16, 41 + y * 10, kColorRed); } else _vm->_graphics->drawNormalText(line, _vm->_font, 8, 16, 41 + y * 10, kColorBlack); } y++; } while (true); // We are now at the end of the text. Next we must read the icons: y = 0; _buttonNum = 0; while (!file.eos()) { int trigger = file.readByte(); if (trigger == 177) break; switch (trigger) { case 254: // Escape trigger = 27; break; case 214: // PageUp trigger = 280; break; case 216: // PageDown trigger = 281; break; default: // A - Z // The characters are stored in the file in uppercase, but we need the lowercase versions for KeyCode: trigger = tolower(trigger); break; } _buttons[y]._trigger = Common::KeyCode(trigger); index = file.readByte(); if (_buttons[y]._trigger != Common::KEYCODE_INVALID) _vm->_graphics->helpDrawButton(13 + (y + 1) * 27, index); _buttons[y]._whither = file.readByte(); // This is the position to jump to. Common::String text = ""; switch (_buttons[y]._trigger) { case Common::KEYCODE_ESCAPE: text = Common::String("Esc"); break; case Common::KEYCODE_PAGEUP: text = Common::String(24); break; case Common::KEYCODE_PAGEDOWN: text = Common::String(25); break; default: text = Common::String(toupper(_buttons[y]._trigger)); break; } _vm->_graphics->helpDrawBigText(text, 589 - (text.size() * 8), 18 + (y + 1) * 27, kColorBlack); _vm->_graphics->helpDrawBigText(text, 590 - (text.size() * 8), 17 + (y + 1) * 27, kColorCyan); y++; _buttonNum++; } _vm->_graphics->refreshScreen(); file.close(); }
void Screen::rollCredits() { uint32 loopingMusicId = _vm->_sound->getLoopingMusicId(); // Prepare for the credits by fading down, stoping the music, etc. _vm->_mouse->setMouse(0); _vm->_sound->muteFx(true); _vm->_sound->muteSpeech(true); waitForFade(); fadeDown(); waitForFade(); _vm->_mouse->closeMenuImmediately(); // There are three files which I believe are involved in showing the // credits: // // credits.bmp - The "Smacker" logo, stored as follows: // // width 2 bytes, little endian // height 2 bytes, little endian // palette 3 * 256 bytes // data width * height bytes // // Note that the maximum colour component in the palette is 0x3F. // This is the same resolution as the _paletteMatch table. I doubt // that this is a coincidence, but let's use the image palette // directly anyway, just to be safe. // // credits.clu - The credits text (credits.txt in PSX version) // // This is simply a text file with CRLF line endings. // '^' is not shown, but used to mark the center of the line. // '@' is used as a placeholder for the "Smacker" logo. At least // when it appears alone. // Remaining lines are centered. // The German version also contains character code 9 for no // apparent reason. We ignore them. // // fonts.clu - The credits font? // // FIXME: At this time I don't know how to interpret fonts.clu. For // now, let's just the standard speech font instead. SpriteInfo spriteInfo; Common::File f; int i; spriteInfo.isText = false; // Read the "Smacker" logo uint16 logoWidth = 0; uint16 logoHeight = 0; byte *logoData = NULL; byte palette[256 * 3]; if (f.open("credits.bmp")) { logoWidth = f.readUint16LE(); logoHeight = f.readUint16LE(); for (i = 0; i < 256; i++) { palette[i * 3 + 0] = f.readByte() << 2; palette[i * 3 + 1] = f.readByte() << 2; palette[i * 3 + 2] = f.readByte() << 2; } logoData = (byte *)malloc(logoWidth * logoHeight); f.read(logoData, logoWidth * logoHeight); f.close(); } else { warning("Can't find credits.bmp"); memset(palette, 0, sizeof(palette)); palette[14 * 3 + 0] = 252; palette[14 * 3 + 1] = 252; palette[14 * 3 + 2] = 252; } setPalette(0, 256, palette, RDPAL_INSTANT); // Read the credits text Common::Array<CreditsLine *> creditsLines; int lineCount = 0; int lineTop = 400; int paragraphStart = 0; bool hasCenterMark = false; if (Sword2Engine::isPsx()) { if (!f.open("credits.txt")) { warning("Can't find credits.txt"); free(logoData); return; } } else { if (!f.open("credits.clu")) { warning("Can't find credits.clu"); free(logoData); return; } } while (1) { char buffer[80]; char *line = f.readLine(buffer, sizeof(buffer)); if (line) { // Replace invalid character codes prevent the 'dud' // symbol from showing up in the credits. for (byte *ptr = (byte *)line; *ptr; ptr++) { switch (*ptr) { case 9: // The German credits contain these. // Convert them to spaces. *ptr = 32; break; case 10: // LF is treated as end of line. *ptr = 0; break; case 170: // The Spanish credits contain these. // Convert them to periods. *ptr = '.'; default: break; } } } if (!line || *line == 0) { if (!hasCenterMark) { for (i = paragraphStart; i < lineCount; i++) creditsLines[i]->type = LINE_CENTER; } paragraphStart = lineCount; hasCenterMark = false; if (paragraphStart == lineCount) lineTop += CREDITS_LINE_SPACING; if (!line) break; continue; } char *center_mark = strchr(line, '^'); if (center_mark) { // The current paragraph has at least one center mark. hasCenterMark = true; if (center_mark != line) { creditsLines.push_back(new CreditsLine); // The center mark is somewhere inside the // line. Split it into left and right side. *center_mark = 0; creditsLines[lineCount]->top = lineTop; creditsLines[lineCount]->height = CREDITS_FONT_HEIGHT; creditsLines[lineCount]->type = LINE_LEFT; creditsLines[lineCount]->str = strdup(line); lineCount++; *center_mark = '^'; } line = center_mark; } creditsLines.push_back(new CreditsLine); creditsLines[lineCount]->top = lineTop; if (*line == '^') { creditsLines[lineCount]->type = LINE_RIGHT; line++; } else creditsLines[lineCount]->type = LINE_LEFT; if (strcmp(line, "@") == 0) { creditsLines[lineCount]->height = logoHeight; lineTop += logoHeight; } else { creditsLines[lineCount]->height = CREDITS_FONT_HEIGHT; lineTop += CREDITS_LINE_SPACING; } creditsLines[lineCount]->str = strdup(line); lineCount++; } f.close(); // We could easily add some ScummVM stuff to the credits, if we wanted // to. On the other hand, anyone with the attention span to actually // read all the credits probably already knows. :-) // Start the music and roll the credits // The credits music (which can also be heard briefly in the "carib" // cutscene) is played once. _vm->_sound->streamCompMusic(309, false); clearScene(); fadeUp(0); spriteInfo.scale = 0; spriteInfo.scaledWidth = 0; spriteInfo.scaledHeight = 0; spriteInfo.type = RDSPR_DISPLAYALIGN | RDSPR_NOCOMPRESSION | RDSPR_TRANS; spriteInfo.blend = 0; int startLine = 0; int scrollPos = 0; bool abortCredits = false; int scrollSteps = lineTop + CREDITS_FONT_HEIGHT; uint32 musicStart = getTick(); // Ideally the music should last just a tiny bit longer than the // credits. Note that musicTimeRemaining() will return 0 if the music // is muted, so we need a sensible fallback for that case. uint32 musicLength = MAX((int32)(1000 * (_vm->_sound->musicTimeRemaining() - 3)), 25 * (int32)scrollSteps); while (scrollPos < scrollSteps && !_vm->shouldQuit()) { clearScene(); for (i = startLine; i < lineCount; i++) { if (!creditsLines[i]) continue; // Free any sprites that have scrolled off the screen if (creditsLines[i]->top + creditsLines[i]->height < scrollPos) { debug(2, "Freeing line %d: '%s'", i, creditsLines[i]->str); delete creditsLines[i]; creditsLines[i] = NULL; startLine = i + 1; } else if (creditsLines[i]->top < scrollPos + 400) { if (!creditsLines[i]->sprite) { debug(2, "Creating line %d: '%s'", i, creditsLines[i]->str); creditsLines[i]->sprite = _vm->_fontRenderer->makeTextSprite((byte *)creditsLines[i]->str, 600, 14, _vm->_speechFontId, 0); } FrameHeader frame; frame.read(creditsLines[i]->sprite); spriteInfo.y = creditsLines[i]->top - scrollPos; spriteInfo.w = frame.width; spriteInfo.h = frame.height; spriteInfo.data = creditsLines[i]->sprite + FrameHeader::size(); spriteInfo.isText = true; switch (creditsLines[i]->type) { case LINE_LEFT: spriteInfo.x = RENDERWIDE / 2 - 5 - frame.width; break; case LINE_RIGHT: spriteInfo.x = RENDERWIDE / 2 + 5; break; case LINE_CENTER: if (strcmp(creditsLines[i]->str, "@") == 0) { spriteInfo.data = logoData; spriteInfo.x = (RENDERWIDE - logoWidth) / 2; spriteInfo.w = logoWidth; spriteInfo.h = logoHeight; } else spriteInfo.x = (RENDERWIDE - frame.width) / 2; break; } if (spriteInfo.data) drawSprite(&spriteInfo); } else break; } updateDisplay(); KeyboardEvent *ke = _vm->keyboardEvent(); if (ke && ke->kbd.keycode == Common::KEYCODE_ESCAPE) { if (!abortCredits) { abortCredits = true; fadeDown(); } } if (abortCredits && getFadeStatus() == RDFADE_BLACK) break; _vm->sleepUntil(musicStart + (musicLength * scrollPos) / scrollSteps + _pauseTicks); scrollPos++; } // We're done. Clean up and try to put everything back where it was // before the credits. for (i = 0; i < lineCount; i++) { delete creditsLines[i]; } free(logoData); if (!abortCredits) { fadeDown(); // The music should either have stopped or be about to stop, so // wait for it to really happen. while (_vm->_sound->musicTimeRemaining() && !_vm->shouldQuit()) { updateDisplay(false); _vm->_system->delayMillis(100); } } if (_vm->shouldQuit()) return; waitForFade(); _vm->_sound->muteFx(false); _vm->_sound->muteSpeech(false); if (loopingMusicId) _vm->_sound->streamCompMusic(loopingMusicId, true); else _vm->_sound->stopMusic(false); if (!_vm->_mouse->getMouseStatus() || _vm->_mouse->isChoosing()) _vm->_mouse->setMouse(NORMAL_MOUSE_ID); if (_vm->_logic->readVar(DEAD)) _vm->_mouse->buildSystemMenu(); }
/** * Loads an object file that is in the common VOL resource format. Expects * the file pointer to point to the last field in header, ie. file length. * This is used at least by the V1 booter games. */ int AgiEngine::loadObjects(Common::File &fp) { int flen = fp.readUint16LE(); return readObjects(fp, flen); }
void Menu::readVerbNums(Common::File &f, int dataSize) { // Figure out what language Id is needed byte desiredLanguageId; switch(_vm->getLanguage()) { case Common::EN_ANY: desiredLanguageId = MORTDAT_LANG_ENGLISH; break; case Common::FR_FRA: desiredLanguageId = MORTDAT_LANG_FRENCH; break; case Common::DE_DEU: desiredLanguageId = MORTDAT_LANG_GERMAN; break; default: warning("Language not supported, switching to English"); desiredLanguageId = MORTDAT_LANG_ENGLISH; break; } // Read in the language byte languageId = f.readByte(); --dataSize; // If the language isn't correct, then skip the entire block if (languageId != desiredLanguageId) { f.skip(dataSize); return; } assert(dataSize == 52); _opcodeAttach = f.readUint16LE(); _opcodeWait = f.readUint16LE(); _opcodeForce = f.readUint16LE(); _opcodeSleep = f.readUint16LE(); _opcodeListen = f.readUint16LE(); _opcodeEnter = f.readUint16LE(); _opcodeClose = f.readUint16LE(); _opcodeSearch = f.readUint16LE(); _opcodeKnock = f.readUint16LE(); _opcodeScratch = f.readUint16LE(); _opcodeRead = f.readUint16LE(); _opcodeEat = f.readUint16LE(); _opcodePlace = f.readUint16LE(); _opcodeOpen = f.readUint16LE(); _opcodeTake = f.readUint16LE(); _opcodeLook = f.readUint16LE(); _opcodeSmell = f.readUint16LE(); _opcodeSound = f.readUint16LE(); _opcodeLeave = f.readUint16LE(); _opcodeLift = f.readUint16LE(); _opcodeTurn = f.readUint16LE(); _opcodeSHide = f.readUint16LE(); _opcodeSSearch = f.readUint16LE(); _opcodeSRead = f.readUint16LE(); _opcodeSPut = f.readUint16LE(); _opcodeSLook = f.readUint16LE(); _actionMenu[0]._menuId = OPCODE_NONE >> 8; _actionMenu[0]._actionId = OPCODE_NONE & 0xFF; _actionMenu[1]._menuId = _opcodeSHide >> 8; _actionMenu[1]._actionId = _opcodeSHide & 0xFF; _actionMenu[2]._menuId = _opcodeAttach >> 8; _actionMenu[2]._actionId = _opcodeAttach & 0xFF; _actionMenu[3]._menuId = _opcodeForce >> 8; _actionMenu[3]._actionId = _opcodeForce & 0xFF; _actionMenu[4]._menuId = _opcodeSleep >> 8; _actionMenu[4]._actionId = _opcodeSleep & 0xFF; _actionMenu[5]._menuId = _opcodeEnter >> 8; _actionMenu[5]._actionId = _opcodeEnter & 0xFF; _actionMenu[6]._menuId = _opcodeClose >> 8; _actionMenu[6]._actionId = _opcodeClose & 0xFF; _actionMenu[7]._menuId = _opcodeKnock >> 8; _actionMenu[7]._actionId = _opcodeKnock & 0xFF; _actionMenu[8]._menuId = _opcodeEat >> 8; _actionMenu[8]._actionId = _opcodeEat & 0xFF; _actionMenu[9]._menuId = _opcodePlace >> 8; _actionMenu[9]._actionId = _opcodePlace & 0xFF; _actionMenu[10]._menuId = _opcodeOpen >> 8; _actionMenu[10]._actionId = _opcodeOpen & 0xFF; _actionMenu[11]._menuId = _opcodeLeave >> 8; _actionMenu[11]._actionId = _opcodeLeave & 0xFF; }
bool Sound::startSpeech(uint16 roomNo, uint16 localNo) { if (_cowHeader == NULL) { warning("Sound::startSpeech: COW file isn't open"); return false; } uint32 locIndex = 0xFFFFFFFF; uint32 sampleSize = 0; uint32 index = 0; if (_cowMode == CowPSX) { Common::File file; uint16 i; if (!file.open("speech.lis")) { warning ("Could not open speech.lis"); return false; } for (i = 0; !file.eos() && !file.err(); i++) if (file.readUint16LE() == roomNo) { locIndex = i; break; } file.close(); if (locIndex == 0xFFFFFFFF) { warning ("Could not find room %d in speech.lis", roomNo); return false; } if (!file.open("speech.inf")) { warning ("Could not open speech.inf"); return false; } uint16 numRooms = file.readUint16LE(); // Read number of rooms referenced in this file file.seek(locIndex * 4 + 2); // 4 bytes per room, skip first 2 bytes uint16 numLines = file.readUint16LE(); uint16 roomOffset = file.readUint16LE(); file.seek(2 + numRooms * 4 + roomOffset * 2); // The offset is in terms of uint16's, so multiply by 2. Skip the room indexes too. locIndex = 0xFFFFFFFF; for (i = 0; i < numLines; i++) if (file.readUint16LE() == localNo) { locIndex = i; break; } if (locIndex == 0xFFFFFFFF) { warning ("Could not find local number %d in room %d in speech.inf", roomNo, localNo); return false; } file.close(); index = _cowHeader[(roomOffset + locIndex) * 2]; sampleSize = _cowHeader[(roomOffset + locIndex) * 2 + 1]; } else { locIndex = _cowHeader[roomNo] >> 2; sampleSize = _cowHeader[locIndex + (localNo * 2)]; index = _cowHeader[locIndex + (localNo * 2) - 1]; } debug(6, "startSpeech(%d, %d): locIndex %d, sampleSize %d, index %d", roomNo, localNo, locIndex, sampleSize, index); Audio::AudioStream *stream = 0; if (sampleSize) { uint8 speechVol = (_speechVolR + _speechVolL) / 2; int8 speechPan = (_speechVolR - _speechVolL) / 2; if ((_cowMode == CowWave) || (_cowMode == CowDemo)) { uint32 size; int16 *data = uncompressSpeech(index + _cowHeaderSize, sampleSize, &size); if (data) { stream = Audio::makeRawStream((byte *)data, size, 11025, SPEECH_FLAGS); _mixer->playStream(Audio::Mixer::kSpeechSoundType, &_speechHandle, stream, SOUND_SPEECH_ID, speechVol, speechPan); } } else if (_cowMode == CowPSX && sampleSize != 0xffffffff) { _cowFile.seek(index * 2048); Common::SeekableReadStream *tmp = _cowFile.readStream(sampleSize); assert(tmp); stream = Audio::makeVagStream(tmp); _mixer->playStream(Audio::Mixer::kSpeechSoundType, &_speechHandle, stream, SOUND_SPEECH_ID, speechVol, speechPan); // with compressed audio, we can't calculate the wave volume. // so default to talking. for (int cnt = 0; cnt < 480; cnt++) _waveVolume[cnt] = true; _waveVolPos = 0; } #ifdef USE_FLAC else if (_cowMode == CowFLAC) { _cowFile.seek(index); Common::SeekableReadStream *tmp = _cowFile.readStream(sampleSize); assert(tmp); stream = Audio::makeFLACStream(tmp, DisposeAfterUse::YES); _mixer->playStream(Audio::Mixer::kSpeechSoundType, &_speechHandle, stream, SOUND_SPEECH_ID, speechVol, speechPan); // with compressed audio, we can't calculate the wave volume. // so default to talking. for (int cnt = 0; cnt < 480; cnt++) _waveVolume[cnt] = true; _waveVolPos = 0; } #endif #ifdef USE_VORBIS else if (_cowMode == CowVorbis) { _cowFile.seek(index); Common::SeekableReadStream *tmp = _cowFile.readStream(sampleSize); assert(tmp); stream = Audio::makeVorbisStream(tmp, DisposeAfterUse::YES); _mixer->playStream(Audio::Mixer::kSpeechSoundType, &_speechHandle, stream, SOUND_SPEECH_ID, speechVol, speechPan); // with compressed audio, we can't calculate the wave volume. // so default to talking. for (int cnt = 0; cnt < 480; cnt++) _waveVolume[cnt] = true; _waveVolPos = 0; } #endif #ifdef USE_MAD else if (_cowMode == CowMP3) { _cowFile.seek(index); Common::SeekableReadStream *tmp = _cowFile.readStream(sampleSize); assert(tmp); stream = Audio::makeMP3Stream(tmp, DisposeAfterUse::YES); _mixer->playStream(Audio::Mixer::kSpeechSoundType, &_speechHandle, stream, SOUND_SPEECH_ID, speechVol, speechPan); // with compressed audio, we can't calculate the wave volume. // so default to talking. for (int cnt = 0; cnt < 480; cnt++) _waveVolume[cnt] = true; _waveVolPos = 0; } #endif return true; } else return false; }
bool BaseAnimationState::init(const char *name) { #ifdef USE_MPEG2 char tempFile[512]; _mpegDecoder = NULL; _mpegFile = NULL; #ifdef BACKEND_8BIT uint i, p; // Load lookup palettes sprintf(tempFile, "%s.pal", name); Common::File f; if (!f.open(tempFile)) { warning("Cutscene: %s palette missing", tempFile); return false; } p = 0; while (!f.eos()) { _palettes[p].end = f.readUint16LE(); _palettes[p].cnt = f.readUint16LE(); for (i = 0; i < _palettes[p].cnt; i++) { _palettes[p].pal[4 * i] = f.readByte(); _palettes[p].pal[4 * i + 1] = f.readByte(); _palettes[p].pal[4 * i + 2] = f.readByte(); _palettes[p].pal[4 * i + 3] = 0; } for (; i < 256; i++) { _palettes[p].pal[4 * i] = 0; _palettes[p].pal[4 * i + 1] = 0; _palettes[p].pal[4 * i + 2] = 0; _palettes[p].pal[4 * i + 3] = 0; } p++; } f.close(); _palNum = 0; _maxPalNum = p; setPalette(_palettes[_palNum].pal); _lut = _lut2 = _yuvLookup[0]; _curPal = -1; _cr = 0; buildLookup(_palNum, 256); _lut2 = _yuvLookup[1]; _lutCalcNum = (BITDEPTH + _palettes[_palNum].end + 2) / (_palettes[_palNum].end + 2); #else buildLookup(); _overlay = (OverlayColor *)calloc(_movieScale * _movieWidth * _movieScale * _movieHeight, sizeof(OverlayColor)); _sys->showOverlay(); #endif // Open MPEG2 stream _mpegFile = new Common::File(); sprintf(tempFile, "%s.mp2", name); if (!_mpegFile->open(tempFile)) { warning("Cutscene: Could not open %s", tempFile); return false; } // Load and configure decoder _mpegDecoder = mpeg2_init(); if (_mpegDecoder == NULL) { warning("Cutscene: Could not allocate an MPEG2 decoder"); return false; } _mpegInfo = mpeg2_info(_mpegDecoder); _frameNum = 0; return true; #else /* USE_MPEG2 */ return false; #endif }
bool ResourceManager::init() { uint32 i, j; // Until proven differently, assume we're on CD 1. This is so the start // dialog will be able to play any music at all. setCD(1); // We read in the resource info which tells us the names of the // resource cluster files ultimately, although there might be groups // within the clusters at this point it makes no difference. We only // wish to know what resource files there are and what is in each Common::File file; if (!file.open("resource.inf")) { GUIErrorMessage("Broken Sword II: Cannot open resource.inf"); return false; } // The resource.inf file is a simple text file containing the names of // all the resource files. while (1) { char *buf = _resFiles[_totalClusters].fileName; uint len = sizeof(_resFiles[_totalClusters].fileName); if (!file.readLine(buf, len)) break; int pos = strlen(buf); if (buf[pos - 1] == 0x0A) buf[pos - 1] = 0; _resFiles[_totalClusters].numEntries = -1; _resFiles[_totalClusters].entryTab = NULL; if (++_totalClusters >= MAX_res_files) { GUIErrorMessage("Broken Sword II: Too many entries in resource.inf"); return false; } } file.close(); // Now load in the binary id to res conversion table if (!file.open("resource.tab")) { GUIErrorMessage("Broken Sword II: Cannot open resource.tab"); return false; } // Find how many resources uint32 size = file.size(); _totalResFiles = size / 4; // Table seems ok so malloc some space _resConvTable = (uint16 *)malloc(size); for (i = 0; i < size / 2; i++) _resConvTable[i] = file.readUint16LE(); if (file.eos() || file.err()) { file.close(); GUIErrorMessage("Broken Sword II: Cannot read resource.tab"); return false; } file.close(); // Check that we have cd.inf file, unless we are running PSX // version, which has all files on one disc. if (!file.open("cd.inf") && !Sword2Engine::isPsx()) { GUIErrorMessage("Broken Sword II: Cannot open cd.inf"); return false; } CdInf *cdInf = new CdInf[_totalClusters]; for (i = 0; i < _totalClusters; i++) { if (Sword2Engine::isPsx()) { // We are running PSX version, artificially fill CdInf structure cdInf[i].cd = CD1; } else { // We are running PC version, read cd.inf file file.read(cdInf[i].clusterName, sizeof(cdInf[i].clusterName)); cdInf[i].cd = file.readByte(); if (file.eos() || file.err()) { delete[] cdInf; file.close(); GUIErrorMessage("Broken Sword II: Cannot read cd.inf"); return false; } } // It has been reported that there are two different versions // of the cd.inf file: One where all clusters on CD also have // the LOCAL_CACHE bit set. This bit is no longer used. To // avoid future problems, let's normalize the flag once and for // all here. if (cdInf[i].cd & LOCAL_PERM) cdInf[i].cd = 0; else if (cdInf[i].cd & CD1) cdInf[i].cd = 1; else if (cdInf[i].cd & CD2) cdInf[i].cd = 2; else cdInf[i].cd = 0; // Any file on "CD 0" may be needed at all times. Verify that // it exists. Any other missing cluster will be requested with // an "insert CD" message. Of course, the file may still vanish // during game-play (oh, that wascally wabbit!) in which case // the resource manager will print a fatal error. if (cdInf[i].cd == 0 && !Common::File::exists((char *)cdInf[i].clusterName)) { GUIErrorMessage("Broken Sword II: Cannot find " + Common::String((char *)cdInf[i].clusterName)); delete[] cdInf; return false; } } file.close(); // We check the presence of resource files in cd.inf // This is ok in PC version, but in PSX version we don't // have cd.inf so we'll have to skip this. if (!Sword2Engine::isPsx()) { for (i = 0; i < _totalClusters; i++) { for (j = 0; j < _totalClusters; j++) { if (scumm_stricmp((char *)cdInf[j].clusterName, _resFiles[i].fileName) == 0) break; } if (j == _totalClusters) { delete[] cdInf; GUIErrorMessage(Common::String(_resFiles[i].fileName) + " is not in cd.inf"); return false; } _resFiles[i].cd = cdInf[j].cd; } } delete[] cdInf; debug(1, "%d resources in %d cluster files", _totalResFiles, _totalClusters); for (i = 0; i < _totalClusters; i++) debug(2, "filename of cluster %d: -%s (%d)", i, _resFiles[i].fileName, _resFiles[i].cd); _resList = (Resource *)malloc(_totalResFiles * sizeof(Resource)); for (i = 0; i < _totalResFiles; i++) { _resList[i].ptr = NULL; _resList[i].size = 0; _resList[i].refCount = 0; _resList[i].prev = _resList[i].next = NULL; } return true; }
void ExtractMMApple::execute() { int i, j; unsigned short signature; char fname[256]; Common::Filename inpath1(_inputPaths[0].path); Common::Filename inpath2(_inputPaths[1].path); Common::Filename &outpath = _outputPath; if (outpath.empty()) // Standard output path outpath.setFullPath("out/"); Common::File input1(inpath1, "rb"); Common::File input2(inpath2, "rb"); input1.seek(142080, SEEK_SET); input2.seek(143104, SEEK_SET); /* check signature */ signature = input1.readUint16LE(); if (signature != 0x0A31) error("Signature not found in disk 1!"); signature = input2.readUint16LE(); if (signature != 0x0032) error("Signature not found in disk 2!"); outpath.setFullName("00.LFL"); Common::File output(outpath, "wb"); // All output should be xored output.setXorMode(0xFF); print("Creating 00.LFL...\n"); /* write signature */ output.writeUint16LE(signature); /* copy object flags */ for (i = 0; i < 256; i++) output.writeByte(input1.readByte()); /* copy room offsets */ for (i = 0; i < NUM_ROOMS; i++) { room_disks_apple[i] = input1.readByte(); output.writeByte(room_disks_apple[i]); } for (i = 0; i < NUM_ROOMS; i++) { room_sectors_apple[i] = input1.readByte(); output.writeByte(room_sectors_apple[i]); room_tracks_apple[i] = input1.readByte(); output.writeByte(room_tracks_apple[i]); } /* copy costume offsets */ for (i = 0; i < 25; i++) output.writeByte(input1.readByte()); for (i = 0; i < 25; i++) output.writeUint16LE(input1.readUint16LE()); /* copy script offsets */ for (i = 0; i < 160; i++) output.writeByte(input1.readByte()); for (i = 0; i < 160; i++) output.writeUint16LE(input1.readUint16LE()); /* copy sound offsets */ for (i = 0; i < 70; i++) output.writeByte(input1.readByte()); for (i = 0; i < 70; i++) output.writeUint16LE(input1.readUint16LE()); /* NOTE: Extra 92 bytes of unknown data */ for (i = 0; i < NUM_ROOMS; i++) { Common::File *input; if (room_disks_apple[i] == '1') input = &input1; else if (room_disks_apple[i] == '2') input = &input2; else continue; sprintf(fname, "%02i.LFL", i); outpath.setFullName(fname); output.open(outpath, "wb"); print("Creating %s...\n", fname); input->seek((SectorOffset[room_tracks_apple[i]] + room_sectors_apple[i]) * 256, SEEK_SET); for (j = 0; j < ResourcesPerFile[i]; j++) { unsigned short len = input->readUint16LE(); output.writeUint16LE(len); for (len -= 2; len > 0; len--) output.writeByte(input->readByte()); } input->rewind(); } print("All done!"); }
bool PatchedFile::load(Common::SeekableReadStream *file, const Common::String &patchName) { uint8 md5_p[16], md5_f[16]; uint32 zctrllen, zdatalen, zextralen; Common::File patch; _patchName = patchName; // Open the patch if (!patch.open(_patchName)) { error("Unable to open patchfile %s", _patchName.c_str()); return false; } // Check for appropriate signature if (patch.readUint32BE() != MKTAG('P','A','T','R')) { error("%s patchfile is corrupted", _patchName.c_str()); return false; } // Check the version number if (patch.readUint16LE() != _kVersionMajor || patch.readUint16LE() > _kVersionMinor) { error("%s has a wrong version number (must be major = %d, minor <= %d)", _patchName.c_str(), _kVersionMajor, _kVersionMinor); return false; } _flags = patch.readUint32LE(); // Check if the file to patch match Common::computeStreamMD5(*file, md5_f, _kMd5size); file->seek(0, SEEK_SET); patch.read(md5_p, 16); if (memcmp(md5_p, md5_f, 16) != 0 || (uint32)file->size() != patch.readUint32LE()) { Debug::debug(Debug::Patchr,"%s targets a different file", _patchName.c_str()); return false; } // Read lengths from header _newSize = patch.readUint32LE(); zctrllen = patch.readUint32LE(); zdatalen = patch.readUint32LE(); zextralen = patch.readUint32LE(); patch.close(); // Opens ctrl, diff and extra substreams Common::File *tmp; tmp = new Common::File; tmp->open(_patchName); _ctrl = new Common::SeekableSubReadStream(tmp, _kHeaderSize, _kHeaderSize + zctrllen, DisposeAfterUse::YES); if (_flags & FLAG_COMPRESS_CTRL) _ctrl = Common::wrapCompressedReadStream(_ctrl); //ctrl stream sanity checks if (_ctrl->size() % (3 * sizeof(uint32)) != 0) { error("%s patchfile is corrupted", _patchName.c_str()); return false; } instrLeft = _ctrl->size() / (3 * sizeof(uint32)); tmp = new Common::File; tmp->open(_patchName); _diff = new Common::SeekableSubReadStream(tmp, _kHeaderSize + zctrllen, _kHeaderSize + zctrllen + zdatalen, DisposeAfterUse::YES); _diff = Common::wrapCompressedReadStream(_diff); if (_flags & FLAG_MIX_DIFF_EXTRA) _extra = _diff; else { tmp = new Common::File; tmp->open(_patchName); _extra = new Common::SeekableSubReadStream(tmp, _kHeaderSize + zctrllen + zdatalen, _kHeaderSize + zctrllen + zdatalen + zextralen, DisposeAfterUse::YES); _extra = Common::wrapCompressedReadStream(_extra); } _file = file; readNextInst(); return true; }
void ExtractZakC64::execute() { int i, j; unsigned short signature; char fname[256]; // Two disks... Common::Filename inpath1(_inputPaths[0].path); Common::Filename inpath2(_inputPaths[1].path); Common::Filename &outpath = _outputPath; if (outpath.empty()) // Standard output path outpath.setFullPath("out/"); Common::File input1(inpath1, "rb"); Common::File input2(inpath2, "rb"); /* check signature */ signature = input1.readUint16LE(); if (signature != 0x0A31) error("Signature not found in disk 1!"); signature = input2.readUint16LE(); if (signature != 0x0132) error("Signature not found in disk 2!"); outpath.setFullName("00.LFL"); Common::File output(outpath, "wb"); output.setXorMode(0xFF); print("Creating 00.LFL..."); /* write signature */ output.writeUint16LE(signature); /* copy object flags */ for (i = 0; i < 775; i++) output.writeByte(input1.readByte()); /* copy room offsets */ for (i = 0; i < NUM_ROOMS; i++) { room_disks_c64[i] = input1.readByte(); output.writeByte(room_disks_c64[i]); } for (i = 0; i < NUM_ROOMS; i++) { room_sectors_c64[i] = input1.readByte(); output.writeByte(room_sectors_c64[i]); room_tracks_c64[i] = input1.readByte(); output.writeByte(room_tracks_c64[i]); } /* copy costume offsets */ for (i = 0; i < 38; i++) output.writeByte(input1.readByte()); for (i = 0; i < 38; i++) output.writeUint16LE(input1.readUint16LE()); /* copy script offsets */ for (i = 0; i < 155; i++) output.writeByte(input1.readByte()); for (i = 0; i < 155; i++) output.writeUint16LE(input1.readUint16LE()); /* copy sound offsets */ for (i = 0; i < 127; i++) output.writeByte(input1.readByte()); for (i = 0; i < 127; i++) output.writeUint16LE(input1.readUint16LE()); output.close(); for (i = 0; i < NUM_ROOMS; i++) { Common::File *input; if (room_disks_c64[i] == '1') input = &input1; else if (room_disks_c64[i] == '2') input = &input2; else continue; sprintf(fname, "%02i.LFL", i); outpath.setFullName(fname); output.open(outpath, "wb"); print("Creating %s...", fname); input->seek((SectorOffset[room_tracks_c64[i]] + room_sectors_c64[i]) * 256, SEEK_SET); for (j = 0; j < ResourcesPerFile[i]; j++) { unsigned short len; do { len = input->readUint16LE(); output.writeUint16LE(len); } while (len == 0xffff); for (len -= 2; len > 0; len--) { output.writeByte(input->readByte()); } } input->rewind(); } print("All done!"); }