/** * Read 32 bit values from a little endian binary file. * * This function will read 32 bit values from a little endian binary file * and convert them to the native byte order. * * Error messages from this function are sent to the message handler * (see msngr_init_log() and msngr_init_mail()). * * @param fd - file descriptor * @param data - pointer to the output data array * @param nvals - number of data values to read * * @return * - number of data values successfully read * - -1 if an error occurred */ int lton_read_32(int fd, void *data, size_t nvals) { ssize_t bytes_read; int vals_read; bytes_read = read(fd, data, 4*nvals); if (bytes_read < 0) { ERROR( ARMUTILS_LIB_NAME, "Could not read data from file: %s\n", strerror(errno)); return(-1); } vals_read = bytes_read/4; #ifdef _BIG_ENDIAN { uint32_t *dp = (uint32_t *)data; int i; for (i = 0; i < vals_read; ++i) { dp[i] = SWAP_BYTES_32(dp[i]); } } #endif return(vals_read); }
void DirectorEngine::loadMac() { if (getVersion() < 4) { // The data is part of the resource fork of the executable _mainArchive = new MacArchive(); if (!_mainArchive->openFile(getEXEName())) error("Failed to open Mac binary '%s'", getEXEName().c_str()); } else { // The RIFX is located in the data fork of the executable _macBinary = new Common::MacResManager(); if (!_macBinary->open(getEXEName()) || !_macBinary->hasDataFork()) error("Failed to open Mac binary '%s'", getEXEName().c_str()); Common::SeekableReadStream *dataFork = _macBinary->getDataFork(); _mainArchive = new RIFXArchive(); // First we need to detect PPC vs. 68k uint32 tag = dataFork->readUint32BE(); uint32 startOffset; if (SWAP_BYTES_32(tag) == MKTAG('P', 'J', '9', '3') || tag == MKTAG('P', 'J', '9', '5') || tag == MKTAG('P', 'J', '0', '0')) { // PPC: The RIFX shares the data fork with the binary startOffset = dataFork->readUint32BE(); } else { // 68k: The RIFX is the only thing in the data fork startOffset = 0; } if (!_mainArchive->openStream(dataFork, startOffset)) error("Failed to load RIFX from Mac binary"); } }
/** * Convert array of 32 bit big endian values to native byte order. * * @param data - pointer to the array of data values * @param nvals - number of values in the data array * * @return pointer to the array of data values */ void *bton_32(void *data, size_t nvals) { #ifndef _BIG_ENDIAN uint32_t *dp = (uint32_t *)data; size_t i; for (i = 0; i < nvals; ++i) { dp[i] = SWAP_BYTES_32(dp[i]); } #endif return(data); }
void OpenGLTexture::byteswapSurface(Graphics::Surface *surface) { for (int y = 0; y < surface->h; y++) { for (int x = 0; x < surface->w; x++) { if (surface->format.bytesPerPixel == 4) { uint32 *pixel = (uint32 *) (surface->getBasePtr(x, y)); *pixel = SWAP_BYTES_32(*pixel); } else if (surface->format.bytesPerPixel == 2) { uint16 *pixel = (uint16 *) (surface->getBasePtr(x, y)); *pixel = SWAP_BYTES_16(*pixel); } else { error("Unexpected bytes per pixedl %d", surface->format.bytesPerPixel); } } } }
bool ResLoaderPak::isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const { int32 filesize = stream.size(); if (filesize < 0) return false; int32 offset = 0; bool switchEndian = false; bool firstFile = true; offset = stream.readUint32LE(); if (offset > filesize || offset < 0) { switchEndian = true; offset = SWAP_BYTES_32(offset); } int32 firstOffset = offset; Common::String file; while (!stream.eos()) { // The start offset of a file should never be in the filelist if (offset < stream.pos() || offset > filesize || offset < 0) return false; file = readString(stream); if (stream.eos()) return false; // Quit now if we encounter an empty string if (file.empty()) { if (firstFile) return false; else break; } firstFile = false; offset = switchEndian ? stream.readUint32BE() : stream.readUint32LE(); if (!offset || offset == filesize || firstOffset == stream.pos()) break; } return true; }
bool SaveConverter::swapDataEndian(byte *data, const byte *sizes, uint32 count) { if (!data || !sizes || (count == 0)) return false; while (count-- > 0) { if (*sizes == 3) // 32bit value (3 additional bytes) WRITE_UINT32(data, SWAP_BYTES_32(READ_UINT32(data))); else if (*sizes == 1) // 16bit value (1 additional byte) WRITE_UINT16(data, SWAP_BYTES_16(READ_UINT16(data))); else if (*sizes != 0) // else, it has to be an 8bit value return false; count -= *sizes; data += *sizes + 1; sizes += *sizes + 1; } return true; }
Codec *createBitmapCodec(uint32 tag, int width, int height, int bitsPerPixel) { switch (tag) { case SWAP_CONSTANT_32(0): return new BitmapRawDecoder(width, height, bitsPerPixel); case SWAP_CONSTANT_32(1): return new MSRLEDecoder(width, height, bitsPerPixel); case SWAP_CONSTANT_32(2): return new MSRLE4Decoder(width, height, bitsPerPixel); case MKTAG('C','R','A','M'): case MKTAG('m','s','v','c'): case MKTAG('W','H','A','M'): return new MSVideo1Decoder(width, height, bitsPerPixel); case MKTAG('c','v','i','d'): return new CinepakDecoder(bitsPerPixel); case MKTAG('I','V','3','2'): return new Indeo3Decoder(width, height); case MKTAG('I', 'V', '4', '1'): case MKTAG('I', 'V', '4', '2'): return new Indeo4Decoder(width, height); case MKTAG('I', 'V', '5', '0'): return new Indeo5Decoder(width, height); #ifdef IMAGE_CODECS_TRUEMOTION1_H case MKTAG('D','U','C','K'): case MKTAG('d','u','c','k'): return new TrueMotion1Decoder(); #endif #ifdef USE_MPEG2 case MKTAG('m','p','g','2'): return new MPEGDecoder(); #endif case MKTAG('M','J','P','G'): case MKTAG('m','j','p','g'): return new MJPEGDecoder(); default: if (tag & 0x00FFFFFF) warning("Unknown BMP/AVI compression format \'%s\'", tag2str(tag)); else warning("Unknown BMP/AVI compression format %d", SWAP_BYTES_32(tag)); } return 0; }
void SagaEngine::load(const char *fileName) { Common::InSaveFile *in; int commonBufferSize; int sceneNumber, insetSceneNumber; int mapx, mapy; char title[TITLESIZE]; if (!(in = _saveFileMan->openForLoading(fileName))) { return; } _saveHeader.type = in->readUint32BE(); _saveHeader.size = in->readUint32LE(); _saveHeader.version = in->readUint32LE(); in->read(_saveHeader.name, sizeof(_saveHeader.name)); // Some older saves were not written in an endian safe fashion. // We try to detect this here by checking for extremly high version values. // If found, we retry with the data swapped. if (_saveHeader.version > 0xFFFFFF) { warning("This savegame is not endian safe, retrying with the data swapped"); _saveHeader.version = SWAP_BYTES_32(_saveHeader.version); } debug(2, "Save version: 0x%X", _saveHeader.version); if (_saveHeader.version < 4) warning("This savegame is not endian-safe. There may be problems"); if (_saveHeader.type != MKTAG('S','A','G','A')) { error("SagaEngine::load wrong save game format"); } if (_saveHeader.version > 4) { in->read(title, TITLESIZE); debug(0, "Save is for: %s", title); } if (_saveHeader.version >= 6) { // We don't need the thumbnail here, so just read it and discard it Graphics::skipThumbnail(*in); in->readUint32BE(); // save date in->readUint16BE(); // save time if (_saveHeader.version >= 8) { uint32 playTime = in->readUint32BE(); g_engine->setTotalPlayTime(playTime * 1000); } } // Clear pending events here, and don't process queued music events _events->clearList(false); // Surrounding scene sceneNumber = in->readSint32LE(); #ifdef ENABLE_IHNM if (getGameId() == GID_IHNM) { int currentChapter = _scene->currentChapterNumber(); _scene->setChapterNumber(in->readSint32LE()); in->skip(4); // obsolete, was used for setting the protagonist if (_scene->currentChapterNumber() != currentChapter) _scene->changeScene(-2, 0, kTransitionFade, _scene->currentChapterNumber()); _scene->setCurrentMusicTrack(in->readSint32LE()); _scene->setCurrentMusicRepeat(in->readSint32LE()); _music->stop(); if (_scene->currentChapterNumber() == 8) _interface->setMode(kPanelChapterSelection); if (!isIHNMDemo()) { _music->play(_music->_songTable[_scene->getCurrentMusicTrack()], _scene->getCurrentMusicRepeat() ? MUSIC_LOOP : MUSIC_NORMAL); } else { _music->play(3, MUSIC_LOOP); } } #endif // Inset scene insetSceneNumber = in->readSint32LE(); #ifdef ENABLE_IHNM if (getGameId() == GID_IHNM) { _globalFlags = in->readUint32LE(); for (int i = 0; i < ARRAYSIZE(_ethicsPoints); i++) _ethicsPoints[i] = in->readSint16LE(); } #endif _interface->loadState(in); _actor->loadState(in); commonBufferSize = in->readSint16LE(); _script->_commonBuffer.resize(commonBufferSize); in->read(_script->_commonBuffer.getBuffer(), commonBufferSize); if (getGameId() == GID_ITE) { mapx = in->readSint16LE(); mapy = in->readSint16LE(); _isoMap->setMapPosition(mapx, mapy); } // Note: the mapx, mapy ISO map positions were incorrectly saved // for IHNM too, which has no ISO map scenes, up to save version 6. // Since they're at the end of the savegame, we just ignore them delete in; // Mute volume to prevent outScene music play int volume = _music->getVolume(); _music->setVolume(0); _scene->clearSceneQueue(); _scene->changeScene(sceneNumber, ACTOR_NO_ENTRANCE, kTransitionNoFade); _events->handleEvents(0); //dissolve backgrounds if (insetSceneNumber != sceneNumber) { _render->setFlag(RF_DISABLE_ACTORS); _scene->draw(); _render->drawScene(); _render->clearFlag(RF_DISABLE_ACTORS); _scene->changeScene(insetSceneNumber, ACTOR_NO_ENTRANCE, kTransitionNoFade); } _music->setVolume(volume); _interface->draw(); // Abort any scene entry protagonist animations and auto-cue speeches. // Fixes bug #10009. _actor->abortAllSpeeches(); _actor->_protagonist->_location = _actor->_protagonist->_finalTarget; _actor->actorEndWalk(ID_PROTAG, true); }
Common::Archive *ResLoaderPak::load(Common::ArchiveMemberPtr memberFile, Common::SeekableReadStream &stream) const { int32 filesize = stream.size(); if (filesize < 0) return 0; Common::ScopedPtr<PlainArchive> result(new PlainArchive(memberFile)); if (!result) return 0; int32 startoffset = 0, endoffset = 0; bool switchEndian = false; bool firstFile = true; startoffset = stream.readUint32LE(); int32 firstOffset = startoffset; if (startoffset > filesize || startoffset < 0) { switchEndian = true; startoffset = SWAP_BYTES_32(startoffset); } Common::String file; while (!stream.eos()) { // The start offset of a file should never be in the filelist if (startoffset < stream.pos() || startoffset > filesize || startoffset < 0) { warning("PAK file '%s' is corrupted", memberFile->getDisplayName().c_str()); return 0; } file = readString(stream); if (stream.eos()) { warning("PAK file '%s' is corrupted", memberFile->getDisplayName().c_str()); return 0; } // Quit now if we encounter an empty string if (file.empty()) { if (firstFile) { warning("PAK file '%s' is corrupted", memberFile->getDisplayName().c_str()); return 0; } else { break; } } firstFile = false; endoffset = switchEndian ? stream.readUint32BE() : stream.readUint32LE(); if (endoffset < 0 && stream.pos() != firstOffset) { warning("PAK file '%s' is corrupted", memberFile->getDisplayName().c_str()); return 0; } if (!endoffset || stream.pos() == firstOffset) endoffset = filesize; if (startoffset != endoffset) result->addFileEntry(file, PlainArchive::Entry(startoffset, endoffset - startoffset)); if (endoffset == filesize) break; startoffset = endoffset; } PlainArchive::Entry linklistFile = result->getFileEntry("LINKLIST"); if (linklistFile.size != 0) { stream.seek(linklistFile.offset, SEEK_SET); const uint32 magic = stream.readUint32BE(); if (magic != MKTAG('S', 'C', 'V', 'M')) error("LINKLIST file does not contain 'SCVM' header"); const uint32 links = stream.readUint32BE(); for (uint32 i = 0; i < links; ++i) { const Common::String linksTo = readString(stream); const uint32 sources = stream.readUint32BE(); PlainArchive::Entry destination = result->getFileEntry(linksTo); if (destination.size == 0) error("PAK file link destination '%s' not found", linksTo.c_str()); for (uint32 j = 0; j < sources; ++j) { const Common::String dest = readString(stream); result->addFileEntry(dest, destination); } } } return result.release(); }
SaveStateDescriptor SagaMetaEngine::querySaveMetaInfos(const char *target, int slot) const { static char fileName[MAX_FILE_NAME]; sprintf(fileName, "%s.s%02d", target, slot); char title[TITLESIZE]; Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(fileName); if (in) { uint32 type = in->readUint32BE(); in->readUint32LE(); // size uint32 version = in->readUint32LE(); char name[SAVE_TITLE_SIZE]; in->read(name, sizeof(name)); SaveStateDescriptor desc(slot, name); // Some older saves were not written in an endian safe fashion. // We try to detect this here by checking for extremly high version values. // If found, we retry with the data swapped. if (version > 0xFFFFFF) { warning("This savegame is not endian safe, retrying with the data swapped"); version = SWAP_BYTES_32(version); } debug(2, "Save version: 0x%X", version); if (version < 4) warning("This savegame is not endian-safe. There may be problems"); if (type != MKTAG('S','A','G','A')) { error("SagaEngine::load wrong save game format"); } if (version > 4) { in->read(title, TITLESIZE); debug(0, "Save is for: %s", title); } if (version >= 6) { Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*in); desc.setThumbnail(thumbnail); uint32 saveDate = in->readUint32BE(); uint16 saveTime = in->readUint16BE(); int day = (saveDate >> 24) & 0xFF; int month = (saveDate >> 16) & 0xFF; int year = saveDate & 0xFFFF; desc.setSaveDate(year, month, day); int hour = (saveTime >> 8) & 0xFF; int minutes = saveTime & 0xFF; desc.setSaveTime(hour, minutes); if (version >= 8) { uint32 playTime = in->readUint32BE(); desc.setPlayTime(playTime * 1000); } } delete in; return desc; }
/** * Opens and inits all sound sample files. */ void SoundManager::openSampleFiles() { // Floppy and demo versions have no sample files, except for the Discworld 2 demo if (_vm->getFeatures() & GF_FLOPPY || (IsDemo && !TinselV2)) return; TinselFile f; if (_sampleIndex) // already allocated return; // open sample index file in binary mode if (f.open(_vm->getSampleIndex(sampleLanguage))) { // get length of index file f.seek(0, SEEK_END); // move to end of file _sampleIndexLen = f.pos(); // get file pointer f.seek(0, SEEK_SET); // back to beginning if (_sampleIndex == NULL) { // allocate a buffer for the indices _sampleIndex = (uint32 *)malloc(_sampleIndexLen); // make sure memory allocated if (_sampleIndex == NULL) { // disable samples if cannot alloc buffer for indices // TODO: Disabled sound if we can't load the sample index? return; } } // load data if (f.read(_sampleIndex, _sampleIndexLen) != (uint32)_sampleIndexLen) // file must be corrupt if we get to here error(FILE_IS_CORRUPT, _vm->getSampleFile(sampleLanguage)); // close the file f.close(); // convert file size to size in DWORDs _sampleIndexLen /= sizeof(uint32); #ifdef SCUMM_BIG_ENDIAN // Convert all ids from LE to native format for (int i = 0; i < _sampleIndexLen; ++i) { _sampleIndex[i] = SWAP_BYTES_32(_sampleIndex[i]); } #endif // Detect format of soundfile by looking at 1st sample-index switch (TO_BE_32(_sampleIndex[0])) { case MKID_BE('MP3 '): debugC(DEBUG_DETAILED, kTinselDebugSound, "Detected MP3 sound-data"); _soundMode = kMP3Mode; break; case MKID_BE('OGG '): debugC(DEBUG_DETAILED, kTinselDebugSound, "Detected OGG sound-data"); _soundMode = kVorbisMode; break; case MKID_BE('FLAC'): debugC(DEBUG_DETAILED, kTinselDebugSound, "Detected FLAC sound-data"); _soundMode = kFLACMode; break; default: debugC(DEBUG_DETAILED, kTinselDebugSound, "Detected original sound-data"); break; } // Normally the 1st sample-index points to nothing at all _sampleIndex[0] = 0; } else { char buf[50]; sprintf(buf, CANNOT_FIND_FILE, _vm->getSampleIndex(sampleLanguage)); GUI::MessageDialog dialog(buf, "OK"); dialog.runModal(); error(CANNOT_FIND_FILE, _vm->getSampleIndex(sampleLanguage)); } // open sample file in binary mode if (!_sampleStream.open(_vm->getSampleFile(sampleLanguage))) { char buf[50]; sprintf(buf, CANNOT_FIND_FILE, _vm->getSampleFile(sampleLanguage)); GUI::MessageDialog dialog(buf, "OK"); dialog.runModal(); error(CANNOT_FIND_FILE, _vm->getSampleFile(sampleLanguage)); } /* // gen length of the largest sample sampleBuffer.size = _sampleStream.readUint32LE(); if (_sampleStream.eos() || _sampleStream.err()) error(FILE_IS_CORRUPT, _vm->getSampleFile(sampleLanguage)); */ }