Example #1
0
/**
 *  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);
}
Example #2
0
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");
    }
}
Example #3
0
/**
 *  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);
}
Example #4
0
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);
			}
		}
	}
}
Example #5
0
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;
}
Example #6
0
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;
}
Example #7
0
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;
}
Example #8
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);
}
Example #9
0
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();
}
Example #10
0
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;
	}
Example #11
0
/**
 * 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));
*/
}